Bitcoin Core 28.99.0
P2P Digital Currency
blockchain.cpp
Go to the documentation of this file.
1// Copyright (c) 2010 Satoshi Nakamoto
2// Copyright (c) 2009-2022 The Bitcoin Core developers
3// Distributed under the MIT software license, see the accompanying
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6#include <rpc/blockchain.h>
7
8#include <blockfilter.h>
9#include <chain.h>
10#include <chainparams.h>
11#include <chainparamsbase.h>
12#include <clientversion.h>
13#include <coins.h>
14#include <common/args.h>
15#include <consensus/amount.h>
16#include <consensus/params.h>
18#include <core_io.h>
19#include <deploymentinfo.h>
20#include <deploymentstatus.h>
21#include <flatfile.h>
22#include <hash.h>
25#include <interfaces/mining.h>
26#include <kernel/coinstats.h>
27#include <logging/timer.h>
28#include <net.h>
29#include <net_processing.h>
30#include <node/blockstorage.h>
31#include <node/context.h>
32#include <node/transaction.h>
33#include <node/utxo_snapshot.h>
34#include <node/warnings.h>
36#include <rpc/server.h>
37#include <rpc/server_util.h>
38#include <rpc/util.h>
39#include <script/descriptor.h>
40#include <serialize.h>
41#include <streams.h>
42#include <sync.h>
43#include <txdb.h>
44#include <txmempool.h>
45#include <undo.h>
46#include <univalue.h>
47#include <util/check.h>
48#include <util/fs.h>
49#include <util/strencodings.h>
50#include <util/translation.h>
51#include <validation.h>
52#include <validationinterface.h>
53#include <versionbits.h>
54
55#include <stdint.h>
56
57#include <condition_variable>
58#include <iterator>
59#include <memory>
60#include <mutex>
61#include <optional>
62#include <vector>
63
66
72
73std::tuple<std::unique_ptr<CCoinsViewCursor>, CCoinsStats, const CBlockIndex*>
75 Chainstate& chainstate,
76 const std::function<void()>& interruption_point = {})
78
80 Chainstate& chainstate,
81 CCoinsViewCursor* pcursor,
82 CCoinsStats* maybe_stats,
83 const CBlockIndex* tip,
84 AutoFile& afile,
85 const fs::path& path,
86 const fs::path& temppath,
87 const std::function<void()>& interruption_point = {});
88
89/* Calculate the difficulty for a given block index.
90 */
91double GetDifficulty(const CBlockIndex& blockindex)
92{
93 int nShift = (blockindex.nBits >> 24) & 0xff;
94 double dDiff =
95 (double)0x0000ffff / (double)(blockindex.nBits & 0x00ffffff);
96
97 while (nShift < 29)
98 {
99 dDiff *= 256.0;
100 nShift++;
101 }
102 while (nShift > 29)
103 {
104 dDiff /= 256.0;
105 nShift--;
106 }
107
108 return dDiff;
109}
110
111static int ComputeNextBlockAndDepth(const CBlockIndex& tip, const CBlockIndex& blockindex, const CBlockIndex*& next)
112{
113 next = tip.GetAncestor(blockindex.nHeight + 1);
114 if (next && next->pprev == &blockindex) {
115 return tip.nHeight - blockindex.nHeight + 1;
116 }
117 next = nullptr;
118 return &blockindex == &tip ? 1 : -1;
119}
120
121static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateManager& chainman)
122{
124 CChain& active_chain = chainman.ActiveChain();
125
126 if (param.isNum()) {
127 const int height{param.getInt<int>()};
128 if (height < 0) {
129 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d is negative", height));
130 }
131 const int current_tip{active_chain.Height()};
132 if (height > current_tip) {
133 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d after current tip %d", height, current_tip));
134 }
135
136 return active_chain[height];
137 } else {
138 const uint256 hash{ParseHashV(param, "hash_or_height")};
139 const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
140
141 if (!pindex) {
142 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
143 }
144
145 return pindex;
146 }
147}
148
149UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex, const uint256 pow_limit)
150{
151 // Serialize passed information without accessing chain state of the active chain!
152 AssertLockNotHeld(cs_main); // For performance reasons
153
154 UniValue result(UniValue::VOBJ);
155 result.pushKV("hash", blockindex.GetBlockHash().GetHex());
156 const CBlockIndex* pnext;
157 int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
158 result.pushKV("confirmations", confirmations);
159 result.pushKV("height", blockindex.nHeight);
160 result.pushKV("version", blockindex.nVersion);
161 result.pushKV("versionHex", strprintf("%08x", blockindex.nVersion));
162 result.pushKV("merkleroot", blockindex.hashMerkleRoot.GetHex());
163 result.pushKV("time", blockindex.nTime);
164 result.pushKV("mediantime", blockindex.GetMedianTimePast());
165 result.pushKV("nonce", blockindex.nNonce);
166 result.pushKV("bits", strprintf("%08x", blockindex.nBits));
167 result.pushKV("target", GetTarget(tip, pow_limit).GetHex());
168 result.pushKV("difficulty", GetDifficulty(blockindex));
169 result.pushKV("chainwork", blockindex.nChainWork.GetHex());
170 result.pushKV("nTx", blockindex.nTx);
171
172 if (blockindex.pprev)
173 result.pushKV("previousblockhash", blockindex.pprev->GetBlockHash().GetHex());
174 if (pnext)
175 result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
176 return result;
177}
178
179UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity, const uint256 pow_limit)
180{
181 UniValue result = blockheaderToJSON(tip, blockindex, pow_limit);
182
183 result.pushKV("strippedsize", (int)::GetSerializeSize(TX_NO_WITNESS(block)));
184 result.pushKV("size", (int)::GetSerializeSize(TX_WITH_WITNESS(block)));
185 result.pushKV("weight", (int)::GetBlockWeight(block));
187
188 switch (verbosity) {
190 for (const CTransactionRef& tx : block.vtx) {
191 txs.push_back(tx->GetHash().GetHex());
192 }
193 break;
194
197 CBlockUndo blockUndo;
198 const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))};
199 bool have_undo{is_not_pruned && WITH_LOCK(::cs_main, return blockindex.nStatus & BLOCK_HAVE_UNDO)};
200 if (have_undo && !blockman.ReadBlockUndo(blockUndo, blockindex)) {
201 throw JSONRPCError(RPC_INTERNAL_ERROR, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event.");
202 }
203 for (size_t i = 0; i < block.vtx.size(); ++i) {
204 const CTransactionRef& tx = block.vtx.at(i);
205 // coinbase transaction (i.e. i == 0) doesn't have undo data
206 const CTxUndo* txundo = (have_undo && i > 0) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
208 TxToUniv(*tx, /*block_hash=*/uint256(), /*entry=*/objTx, /*include_hex=*/true, txundo, verbosity);
209 txs.push_back(std::move(objTx));
210 }
211 break;
212 }
213
214 result.pushKV("tx", std::move(txs));
215
216 return result;
217}
218
220{
221 return RPCHelpMan{"getblockcount",
222 "\nReturns the height of the most-work fully-validated chain.\n"
223 "The genesis block has height 0.\n",
224 {},
225 RPCResult{
226 RPCResult::Type::NUM, "", "The current block count"},
228 HelpExampleCli("getblockcount", "")
229 + HelpExampleRpc("getblockcount", "")
230 },
231 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
232{
233 ChainstateManager& chainman = EnsureAnyChainman(request.context);
234 LOCK(cs_main);
235 return chainman.ActiveChain().Height();
236},
237 };
238}
239
241{
242 return RPCHelpMan{"getbestblockhash",
243 "\nReturns the hash of the best (tip) block in the most-work fully-validated chain.\n",
244 {},
245 RPCResult{
246 RPCResult::Type::STR_HEX, "", "the block hash, hex-encoded"},
248 HelpExampleCli("getbestblockhash", "")
249 + HelpExampleRpc("getbestblockhash", "")
250 },
251 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
252{
253 ChainstateManager& chainman = EnsureAnyChainman(request.context);
254 LOCK(cs_main);
255 return chainman.ActiveChain().Tip()->GetBlockHash().GetHex();
256},
257 };
258}
259
261{
262 return RPCHelpMan{"waitfornewblock",
263 "\nWaits for any new block and returns useful info about it.\n"
264 "\nReturns the current block on timeout or exit.\n"
265 "\nMake sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
266 {
267 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
268 },
269 RPCResult{
270 RPCResult::Type::OBJ, "", "",
271 {
272 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
273 {RPCResult::Type::NUM, "height", "Block height"},
274 }},
276 HelpExampleCli("waitfornewblock", "1000")
277 + HelpExampleRpc("waitfornewblock", "1000")
278 },
279 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
280{
281 int timeout = 0;
282 if (!request.params[0].isNull())
283 timeout = request.params[0].getInt<int>();
284 if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout");
285
286 NodeContext& node = EnsureAnyNodeContext(request.context);
287 Mining& miner = EnsureMining(node);
288
289 auto block{CHECK_NONFATAL(miner.getTip()).value()};
290 if (IsRPCRunning()) {
291 block = timeout ? miner.waitTipChanged(block.hash, std::chrono::milliseconds(timeout)) : miner.waitTipChanged(block.hash);
292 }
293
295 ret.pushKV("hash", block.hash.GetHex());
296 ret.pushKV("height", block.height);
297 return ret;
298},
299 };
300}
301
303{
304 return RPCHelpMan{"waitforblock",
305 "\nWaits for a specific new block and returns useful info about it.\n"
306 "\nReturns the current block on timeout or exit.\n"
307 "\nMake sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
308 {
309 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Block hash to wait for."},
310 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
311 },
312 RPCResult{
313 RPCResult::Type::OBJ, "", "",
314 {
315 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
316 {RPCResult::Type::NUM, "height", "Block height"},
317 }},
319 HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\" 1000")
320 + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
321 },
322 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
323{
324 int timeout = 0;
325
326 uint256 hash(ParseHashV(request.params[0], "blockhash"));
327
328 if (!request.params[1].isNull())
329 timeout = request.params[1].getInt<int>();
330 if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout");
331
332 NodeContext& node = EnsureAnyNodeContext(request.context);
333 Mining& miner = EnsureMining(node);
334
335 auto block{CHECK_NONFATAL(miner.getTip()).value()};
336 const auto deadline{std::chrono::steady_clock::now() + 1ms * timeout};
337 while (IsRPCRunning() && block.hash != hash) {
338 if (timeout) {
339 auto now{std::chrono::steady_clock::now()};
340 if (now >= deadline) break;
341 const MillisecondsDouble remaining{deadline - now};
342 block = miner.waitTipChanged(block.hash, remaining);
343 } else {
344 block = miner.waitTipChanged(block.hash);
345 }
346 }
347
349 ret.pushKV("hash", block.hash.GetHex());
350 ret.pushKV("height", block.height);
351 return ret;
352},
353 };
354}
355
357{
358 return RPCHelpMan{"waitforblockheight",
359 "\nWaits for (at least) block height and returns the height and hash\n"
360 "of the current tip.\n"
361 "\nReturns the current block on timeout or exit.\n"
362 "\nMake sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
363 {
364 {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "Block height to wait for."},
365 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
366 },
367 RPCResult{
368 RPCResult::Type::OBJ, "", "",
369 {
370 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
371 {RPCResult::Type::NUM, "height", "Block height"},
372 }},
374 HelpExampleCli("waitforblockheight", "100 1000")
375 + HelpExampleRpc("waitforblockheight", "100, 1000")
376 },
377 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
378{
379 int timeout = 0;
380
381 int height = request.params[0].getInt<int>();
382
383 if (!request.params[1].isNull())
384 timeout = request.params[1].getInt<int>();
385 if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout");
386
387 NodeContext& node = EnsureAnyNodeContext(request.context);
388 Mining& miner = EnsureMining(node);
389
390 auto block{CHECK_NONFATAL(miner.getTip()).value()};
391 const auto deadline{std::chrono::steady_clock::now() + 1ms * timeout};
392
393 while (IsRPCRunning() && block.height < height) {
394 if (timeout) {
395 auto now{std::chrono::steady_clock::now()};
396 if (now >= deadline) break;
397 const MillisecondsDouble remaining{deadline - now};
398 block = miner.waitTipChanged(block.hash, remaining);
399 } else {
400 block = miner.waitTipChanged(block.hash);
401 }
402 }
403
405 ret.pushKV("hash", block.hash.GetHex());
406 ret.pushKV("height", block.height);
407 return ret;
408},
409 };
410}
411
413{
414 return RPCHelpMan{"syncwithvalidationinterfacequeue",
415 "\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n",
416 {},
419 HelpExampleCli("syncwithvalidationinterfacequeue","")
420 + HelpExampleRpc("syncwithvalidationinterfacequeue","")
421 },
422 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
423{
424 NodeContext& node = EnsureAnyNodeContext(request.context);
425 CHECK_NONFATAL(node.validation_signals)->SyncWithValidationInterfaceQueue();
426 return UniValue::VNULL;
427},
428 };
429}
430
432{
433 return RPCHelpMan{"getdifficulty",
434 "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n",
435 {},
436 RPCResult{
437 RPCResult::Type::NUM, "", "the proof-of-work difficulty as a multiple of the minimum difficulty."},
439 HelpExampleCli("getdifficulty", "")
440 + HelpExampleRpc("getdifficulty", "")
441 },
442 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
443{
444 ChainstateManager& chainman = EnsureAnyChainman(request.context);
445 LOCK(cs_main);
446 return GetDifficulty(*CHECK_NONFATAL(chainman.ActiveChain().Tip()));
447},
448 };
449}
450
452{
453 return RPCHelpMan{
454 "getblockfrompeer",
455 "Attempt to fetch block from a given peer.\n\n"
456 "We must have the header for this block, e.g. using submitheader.\n"
457 "The block will not have any undo data which can limit the usage of the block data in a context where the undo data is needed.\n"
458 "Subsequent calls for the same block may cause the response from the previous peer to be ignored.\n"
459 "Peers generally ignore requests for a stale block that they never fully verified, or one that is more than a month old.\n"
460 "When a peer does not respond with a block, we will disconnect.\n"
461 "Note: The block could be re-pruned as soon as it is received.\n\n"
462 "Returns an empty JSON object if the request was successfully scheduled.",
463 {
464 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash to try to fetch"},
465 {"peer_id", RPCArg::Type::NUM, RPCArg::Optional::NO, "The peer to fetch it from (see getpeerinfo for peer IDs)"},
466 },
467 RPCResult{RPCResult::Type::OBJ, "", /*optional=*/false, "", {}},
469 HelpExampleCli("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0")
470 + HelpExampleRpc("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0")
471 },
472 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
473{
474 const NodeContext& node = EnsureAnyNodeContext(request.context);
476 PeerManager& peerman = EnsurePeerman(node);
477
478 const uint256& block_hash{ParseHashV(request.params[0], "blockhash")};
479 const NodeId peer_id{request.params[1].getInt<int64_t>()};
480
481 const CBlockIndex* const index = WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(block_hash););
482
483 if (!index) {
484 throw JSONRPCError(RPC_MISC_ERROR, "Block header missing");
485 }
486
487 // Fetching blocks before the node has syncing past their height can prevent block files from
488 // being pruned, so we avoid it if the node is in prune mode.
489 if (chainman.m_blockman.IsPruneMode() && index->nHeight > WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip()->nHeight)) {
490 throw JSONRPCError(RPC_MISC_ERROR, "In prune mode, only blocks that the node has already synced previously can be fetched from a peer");
491 }
492
493 const bool block_has_data = WITH_LOCK(::cs_main, return index->nStatus & BLOCK_HAVE_DATA);
494 if (block_has_data) {
495 throw JSONRPCError(RPC_MISC_ERROR, "Block already downloaded");
496 }
497
498 if (const auto err{peerman.FetchBlock(peer_id, *index)}) {
499 throw JSONRPCError(RPC_MISC_ERROR, err.value());
500 }
501 return UniValue::VOBJ;
502},
503 };
504}
505
507{
508 return RPCHelpMan{"getblockhash",
509 "\nReturns hash of block in best-block-chain at height provided.\n",
510 {
511 {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The height index"},
512 },
513 RPCResult{
514 RPCResult::Type::STR_HEX, "", "The block hash"},
516 HelpExampleCli("getblockhash", "1000")
517 + HelpExampleRpc("getblockhash", "1000")
518 },
519 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
520{
521 ChainstateManager& chainman = EnsureAnyChainman(request.context);
522 LOCK(cs_main);
523 const CChain& active_chain = chainman.ActiveChain();
524
525 int nHeight = request.params[0].getInt<int>();
526 if (nHeight < 0 || nHeight > active_chain.Height())
527 throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
528
529 const CBlockIndex* pblockindex = active_chain[nHeight];
530 return pblockindex->GetBlockHash().GetHex();
531},
532 };
533}
534
536{
537 return RPCHelpMan{"getblockheader",
538 "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"
539 "If verbose is true, returns an Object with information about blockheader <hash>.\n",
540 {
541 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
542 {"verbose", RPCArg::Type::BOOL, RPCArg::Default{true}, "true for a json object, false for the hex-encoded data"},
543 },
544 {
545 RPCResult{"for verbose = true",
546 RPCResult::Type::OBJ, "", "",
547 {
548 {RPCResult::Type::STR_HEX, "hash", "the block hash (same as provided)"},
549 {RPCResult::Type::NUM, "confirmations", "The number of confirmations, or -1 if the block is not on the main chain"},
550 {RPCResult::Type::NUM, "height", "The block height or index"},
551 {RPCResult::Type::NUM, "version", "The block version"},
552 {RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},
553 {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
554 {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
555 {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
556 {RPCResult::Type::NUM, "nonce", "The nonce"},
557 {RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},
558 {RPCResult::Type::STR_HEX, "target", "The difficulty target"},
559 {RPCResult::Type::NUM, "difficulty", "The difficulty"},
560 {RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the current chain"},
561 {RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
562 {RPCResult::Type::STR_HEX, "previousblockhash", /*optional=*/true, "The hash of the previous block (if available)"},
563 {RPCResult::Type::STR_HEX, "nextblockhash", /*optional=*/true, "The hash of the next block (if available)"},
564 }},
565 RPCResult{"for verbose=false",
566 RPCResult::Type::STR_HEX, "", "A string that is serialized, hex-encoded data for block 'hash'"},
567 },
569 HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
570 + HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
571 },
572 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
573{
574 uint256 hash(ParseHashV(request.params[0], "hash"));
575
576 bool fVerbose = true;
577 if (!request.params[1].isNull())
578 fVerbose = request.params[1].get_bool();
579
580 const CBlockIndex* pblockindex;
581 const CBlockIndex* tip;
582 ChainstateManager& chainman = EnsureAnyChainman(request.context);
583 {
584 LOCK(cs_main);
585 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
586 tip = chainman.ActiveChain().Tip();
587 }
588
589 if (!pblockindex) {
590 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
591 }
592
593 if (!fVerbose)
594 {
595 DataStream ssBlock{};
596 ssBlock << pblockindex->GetBlockHeader();
597 std::string strHex = HexStr(ssBlock);
598 return strHex;
599 }
600
601 return blockheaderToJSON(*tip, *pblockindex, chainman.GetConsensus().powLimit);
602},
603 };
604}
605
606void CheckBlockDataAvailability(BlockManager& blockman, const CBlockIndex& blockindex, bool check_for_undo)
607{
609 uint32_t flag = check_for_undo ? BLOCK_HAVE_UNDO : BLOCK_HAVE_DATA;
610 if (!(blockindex.nStatus & flag)) {
611 if (blockman.IsBlockPruned(blockindex)) {
612 throw JSONRPCError(RPC_MISC_ERROR, strprintf("%s not available (pruned data)", check_for_undo ? "Undo data" : "Block"));
613 }
614 if (check_for_undo) {
615 throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available");
616 }
617 throw JSONRPCError(RPC_MISC_ERROR, "Block not available (not fully downloaded)");
618 }
619}
620
621static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex& blockindex)
622{
623 CBlock block;
624 {
625 LOCK(cs_main);
626 CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/false);
627 }
628
629 if (!blockman.ReadBlock(block, blockindex)) {
630 // Block not found on disk. This shouldn't normally happen unless the block was
631 // pruned right after we released the lock above.
632 throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
633 }
634
635 return block;
636}
637
638static std::vector<uint8_t> GetRawBlockChecked(BlockManager& blockman, const CBlockIndex& blockindex)
639{
640 std::vector<uint8_t> data{};
641 FlatFilePos pos{};
642 {
643 LOCK(cs_main);
644 CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/false);
645 pos = blockindex.GetBlockPos();
646 }
647
648 if (!blockman.ReadRawBlock(data, pos)) {
649 // Block not found on disk. This shouldn't normally happen unless the block was
650 // pruned right after we released the lock above.
651 throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
652 }
653
654 return data;
655}
656
657static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex& blockindex)
658{
659 CBlockUndo blockUndo;
660
661 // The Genesis block does not have undo data
662 if (blockindex.nHeight == 0) return blockUndo;
663
664 {
665 LOCK(cs_main);
666 CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/true);
667 }
668
669 if (!blockman.ReadBlockUndo(blockUndo, blockindex)) {
670 throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
671 }
672
673 return blockUndo;
674}
675
677 RPCResult::Type::ARR, "vin", "",
678 {
679 {RPCResult::Type::OBJ, "", "",
680 {
681 {RPCResult::Type::ELISION, "", "The same output as verbosity = 2"},
682 {RPCResult::Type::OBJ, "prevout", "(Only if undo information is available)",
683 {
684 {RPCResult::Type::BOOL, "generated", "Coinbase or not"},
685 {RPCResult::Type::NUM, "height", "The height of the prevout"},
686 {RPCResult::Type::STR_AMOUNT, "value", "The value in " + CURRENCY_UNIT},
687 {RPCResult::Type::OBJ, "scriptPubKey", "",
688 {
689 {RPCResult::Type::STR, "asm", "Disassembly of the output script"},
690 {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
691 {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"},
692 {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
693 {RPCResult::Type::STR, "type", "The type (one of: " + GetAllOutputTypes() + ")"},
694 }},
695 }},
696 }},
697 }
698};
699
701{
702 return RPCHelpMan{"getblock",
703 "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
704 "If verbosity is 1, returns an Object with information about block <hash>.\n"
705 "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction.\n"
706 "If verbosity is 3, returns an Object with information about block <hash> and information about each transaction, including prevout information for inputs (only for unpruned blocks in the current best chain).\n",
707 {
708 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
709 {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1}, "0 for hex-encoded data, 1 for a JSON object, 2 for JSON object with transaction data, and 3 for JSON object with transaction data including prevout information for inputs",
711 },
712 {
713 RPCResult{"for verbosity = 0",
714 RPCResult::Type::STR_HEX, "", "A string that is serialized, hex-encoded data for block 'hash'"},
715 RPCResult{"for verbosity = 1",
716 RPCResult::Type::OBJ, "", "",
717 {
718 {RPCResult::Type::STR_HEX, "hash", "the block hash (same as provided)"},
719 {RPCResult::Type::NUM, "confirmations", "The number of confirmations, or -1 if the block is not on the main chain"},
720 {RPCResult::Type::NUM, "size", "The block size"},
721 {RPCResult::Type::NUM, "strippedsize", "The block size excluding witness data"},
722 {RPCResult::Type::NUM, "weight", "The block weight as defined in BIP 141"},
723 {RPCResult::Type::NUM, "height", "The block height or index"},
724 {RPCResult::Type::NUM, "version", "The block version"},
725 {RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},
726 {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
727 {RPCResult::Type::ARR, "tx", "The transaction ids",
728 {{RPCResult::Type::STR_HEX, "", "The transaction id"}}},
729 {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
730 {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
731 {RPCResult::Type::NUM, "nonce", "The nonce"},
732 {RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},
733 {RPCResult::Type::STR_HEX, "target", "The difficulty target"},
734 {RPCResult::Type::NUM, "difficulty", "The difficulty"},
735 {RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the chain up to this block (in hex)"},
736 {RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
737 {RPCResult::Type::STR_HEX, "previousblockhash", /*optional=*/true, "The hash of the previous block (if available)"},
738 {RPCResult::Type::STR_HEX, "nextblockhash", /*optional=*/true, "The hash of the next block (if available)"},
739 }},
740 RPCResult{"for verbosity = 2",
741 RPCResult::Type::OBJ, "", "",
742 {
743 {RPCResult::Type::ELISION, "", "Same output as verbosity = 1"},
744 {RPCResult::Type::ARR, "tx", "",
745 {
746 {RPCResult::Type::OBJ, "", "",
747 {
748 {RPCResult::Type::ELISION, "", "The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result"},
749 {RPCResult::Type::NUM, "fee", "The transaction fee in " + CURRENCY_UNIT + ", omitted if block undo data is not available"},
750 }},
751 }},
752 }},
753 RPCResult{"for verbosity = 3",
754 RPCResult::Type::OBJ, "", "",
755 {
756 {RPCResult::Type::ELISION, "", "Same output as verbosity = 2"},
757 {RPCResult::Type::ARR, "tx", "",
758 {
759 {RPCResult::Type::OBJ, "", "",
760 {
762 }},
763 }},
764 }},
765 },
767 HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
768 + HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
769 },
770 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
771{
772 uint256 hash(ParseHashV(request.params[0], "blockhash"));
773
774 int verbosity{ParseVerbosity(request.params[1], /*default_verbosity=*/1, /*allow_bool=*/true)};
775
776 const CBlockIndex* pblockindex;
777 const CBlockIndex* tip;
778 ChainstateManager& chainman = EnsureAnyChainman(request.context);
779 {
780 LOCK(cs_main);
781 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
782 tip = chainman.ActiveChain().Tip();
783
784 if (!pblockindex) {
785 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
786 }
787 }
788
789 const std::vector<uint8_t> block_data{GetRawBlockChecked(chainman.m_blockman, *pblockindex)};
790
791 if (verbosity <= 0) {
792 return HexStr(block_data);
793 }
794
795 DataStream block_stream{block_data};
796 CBlock block{};
797 block_stream >> TX_WITH_WITNESS(block);
798
799 TxVerbosity tx_verbosity;
800 if (verbosity == 1) {
801 tx_verbosity = TxVerbosity::SHOW_TXID;
802 } else if (verbosity == 2) {
803 tx_verbosity = TxVerbosity::SHOW_DETAILS;
804 } else {
806 }
807
808 return blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity, chainman.GetConsensus().powLimit);
809},
810 };
811}
812
814std::optional<int> GetPruneHeight(const BlockManager& blockman, const CChain& chain) {
816
817 // Search for the last block missing block data or undo data. Don't let the
818 // search consider the genesis block, because the genesis block does not
819 // have undo data, but should not be considered pruned.
820 const CBlockIndex* first_block{chain[1]};
821 const CBlockIndex* chain_tip{chain.Tip()};
822
823 // If there are no blocks after the genesis block, or no blocks at all, nothing is pruned.
824 if (!first_block || !chain_tip) return std::nullopt;
825
826 // If the chain tip is pruned, everything is pruned.
827 if (!((chain_tip->nStatus & BLOCK_HAVE_MASK) == BLOCK_HAVE_MASK)) return chain_tip->nHeight;
828
829 const auto& first_unpruned{*CHECK_NONFATAL(blockman.GetFirstBlock(*chain_tip, /*status_mask=*/BLOCK_HAVE_MASK, first_block))};
830 if (&first_unpruned == first_block) {
831 // All blocks between first_block and chain_tip have data, so nothing is pruned.
832 return std::nullopt;
833 }
834
835 // Block before the first unpruned block is the last pruned block.
836 return CHECK_NONFATAL(first_unpruned.pprev)->nHeight;
837}
838
840{
841 return RPCHelpMan{"pruneblockchain", "",
842 {
843 {"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"
844 " to prune blocks whose block time is at least 2 hours older than the provided timestamp."},
845 },
846 RPCResult{
847 RPCResult::Type::NUM, "", "Height of the last block pruned"},
849 HelpExampleCli("pruneblockchain", "1000")
850 + HelpExampleRpc("pruneblockchain", "1000")
851 },
852 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
853{
854 ChainstateManager& chainman = EnsureAnyChainman(request.context);
855 if (!chainman.m_blockman.IsPruneMode()) {
856 throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
857 }
858
859 LOCK(cs_main);
860 Chainstate& active_chainstate = chainman.ActiveChainstate();
861 CChain& active_chain = active_chainstate.m_chain;
862
863 int heightParam = request.params[0].getInt<int>();
864 if (heightParam < 0) {
865 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative block height.");
866 }
867
868 // Height value more than a billion is too high to be a block height, and
869 // too low to be a block time (corresponds to timestamp from Sep 2001).
870 if (heightParam > 1000000000) {
871 // Add a 2 hour buffer to include blocks which might have had old timestamps
872 const CBlockIndex* pindex = active_chain.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0);
873 if (!pindex) {
874 throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp.");
875 }
876 heightParam = pindex->nHeight;
877 }
878
879 unsigned int height = (unsigned int) heightParam;
880 unsigned int chainHeight = (unsigned int) active_chain.Height();
881 if (chainHeight < chainman.GetParams().PruneAfterHeight()) {
882 throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning.");
883 } else if (height > chainHeight) {
884 throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height.");
885 } else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
886 LogDebug(BCLog::RPC, "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks.\n");
887 height = chainHeight - MIN_BLOCKS_TO_KEEP;
888 }
889
890 PruneBlockFilesManual(active_chainstate, height);
891 return GetPruneHeight(chainman.m_blockman, active_chain).value_or(-1);
892},
893 };
894}
895
896CoinStatsHashType ParseHashType(const std::string& hash_type_input)
897{
898 if (hash_type_input == "hash_serialized_3") {
899 return CoinStatsHashType::HASH_SERIALIZED;
900 } else if (hash_type_input == "muhash") {
901 return CoinStatsHashType::MUHASH;
902 } else if (hash_type_input == "none") {
904 } else {
905 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("'%s' is not a valid hash_type", hash_type_input));
906 }
907}
908
914static std::optional<kernel::CCoinsStats> GetUTXOStats(CCoinsView* view, node::BlockManager& blockman,
916 const std::function<void()>& interruption_point = {},
917 const CBlockIndex* pindex = nullptr,
918 bool index_requested = true)
919{
920 // Use CoinStatsIndex if it is requested and available and a hash_type of Muhash or None was requested
921 if ((hash_type == kernel::CoinStatsHashType::MUHASH || hash_type == kernel::CoinStatsHashType::NONE) && g_coin_stats_index && index_requested) {
922 if (pindex) {
923 return g_coin_stats_index->LookUpStats(*pindex);
924 } else {
925 CBlockIndex& block_index = *CHECK_NONFATAL(WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(view->GetBestBlock())));
926 return g_coin_stats_index->LookUpStats(block_index);
927 }
928 }
929
930 // If the coinstats index isn't requested or is otherwise not usable, the
931 // pindex should either be null or equal to the view's best block. This is
932 // because without the coinstats index we can only get coinstats about the
933 // best block.
934 CHECK_NONFATAL(!pindex || pindex->GetBlockHash() == view->GetBestBlock());
935
936 return kernel::ComputeUTXOStats(hash_type, view, blockman, interruption_point);
937}
938
940{
941 return RPCHelpMan{"gettxoutsetinfo",
942 "\nReturns statistics about the unspent transaction output set.\n"
943 "Note this call may take some time if you are not using coinstatsindex.\n",
944 {
945 {"hash_type", RPCArg::Type::STR, RPCArg::Default{"hash_serialized_3"}, "Which UTXO set hash should be calculated. Options: 'hash_serialized_3' (the legacy algorithm), 'muhash', 'none'."},
946 {"hash_or_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"the current best block"}, "The block hash or height of the target height (only available with coinstatsindex).",
948 .skip_type_check = true,
949 .type_str = {"", "string or numeric"},
950 }},
951 {"use_index", RPCArg::Type::BOOL, RPCArg::Default{true}, "Use coinstatsindex, if available."},
952 },
953 RPCResult{
954 RPCResult::Type::OBJ, "", "",
955 {
956 {RPCResult::Type::NUM, "height", "The block height (index) of the returned statistics"},
957 {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at which these statistics are calculated"},
958 {RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs"},
959 {RPCResult::Type::NUM, "bogosize", "Database-independent, meaningless metric indicating the UTXO set size"},
960 {RPCResult::Type::STR_HEX, "hash_serialized_3", /*optional=*/true, "The serialized hash (only present if 'hash_serialized_3' hash_type is chosen)"},
961 {RPCResult::Type::STR_HEX, "muhash", /*optional=*/true, "The serialized hash (only present if 'muhash' hash_type is chosen)"},
962 {RPCResult::Type::NUM, "transactions", /*optional=*/true, "The number of transactions with unspent outputs (not available when coinstatsindex is used)"},
963 {RPCResult::Type::NUM, "disk_size", /*optional=*/true, "The estimated size of the chainstate on disk (not available when coinstatsindex is used)"},
964 {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of coins in the UTXO set"},
965 {RPCResult::Type::STR_AMOUNT, "total_unspendable_amount", /*optional=*/true, "The total amount of coins permanently excluded from the UTXO set (only available if coinstatsindex is used)"},
966 {RPCResult::Type::OBJ, "block_info", /*optional=*/true, "Info on amounts in the block at this block height (only available if coinstatsindex is used)",
967 {
968 {RPCResult::Type::STR_AMOUNT, "prevout_spent", "Total amount of all prevouts spent in this block"},
969 {RPCResult::Type::STR_AMOUNT, "coinbase", "Coinbase subsidy amount of this block"},
970 {RPCResult::Type::STR_AMOUNT, "new_outputs_ex_coinbase", "Total amount of new outputs created by this block"},
971 {RPCResult::Type::STR_AMOUNT, "unspendable", "Total amount of unspendable outputs created in this block"},
972 {RPCResult::Type::OBJ, "unspendables", "Detailed view of the unspendable categories",
973 {
974 {RPCResult::Type::STR_AMOUNT, "genesis_block", "The unspendable amount of the Genesis block subsidy"},
975 {RPCResult::Type::STR_AMOUNT, "bip30", "Transactions overridden by duplicates (no longer possible with BIP30)"},
976 {RPCResult::Type::STR_AMOUNT, "scripts", "Amounts sent to scripts that are unspendable (for example OP_RETURN outputs)"},
977 {RPCResult::Type::STR_AMOUNT, "unclaimed_rewards", "Fee rewards that miners did not claim in their coinbase transaction"},
978 }}
979 }},
980 }},
982 HelpExampleCli("gettxoutsetinfo", "") +
983 HelpExampleCli("gettxoutsetinfo", R"("none")") +
984 HelpExampleCli("gettxoutsetinfo", R"("none" 1000)") +
985 HelpExampleCli("gettxoutsetinfo", R"("none" '"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"')") +
986 HelpExampleCli("-named gettxoutsetinfo", R"(hash_type='muhash' use_index='false')") +
987 HelpExampleRpc("gettxoutsetinfo", "") +
988 HelpExampleRpc("gettxoutsetinfo", R"("none")") +
989 HelpExampleRpc("gettxoutsetinfo", R"("none", 1000)") +
990 HelpExampleRpc("gettxoutsetinfo", R"("none", "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09")")
991 },
992 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
993{
995
996 const CBlockIndex* pindex{nullptr};
997 const CoinStatsHashType hash_type{request.params[0].isNull() ? CoinStatsHashType::HASH_SERIALIZED : ParseHashType(request.params[0].get_str())};
998 bool index_requested = request.params[2].isNull() || request.params[2].get_bool();
999
1000 NodeContext& node = EnsureAnyNodeContext(request.context);
1002 Chainstate& active_chainstate = chainman.ActiveChainstate();
1003 active_chainstate.ForceFlushStateToDisk();
1004
1005 CCoinsView* coins_view;
1006 BlockManager* blockman;
1007 {
1008 LOCK(::cs_main);
1009 coins_view = &active_chainstate.CoinsDB();
1010 blockman = &active_chainstate.m_blockman;
1011 pindex = blockman->LookupBlockIndex(coins_view->GetBestBlock());
1012 }
1013
1014 if (!request.params[1].isNull()) {
1015 if (!g_coin_stats_index) {
1016 throw JSONRPCError(RPC_INVALID_PARAMETER, "Querying specific block heights requires coinstatsindex");
1017 }
1018
1019 if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1020 throw JSONRPCError(RPC_INVALID_PARAMETER, "hash_serialized_3 hash type cannot be queried for a specific block");
1021 }
1022
1023 if (!index_requested) {
1024 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot set use_index to false when querying for a specific block");
1025 }
1026 pindex = ParseHashOrHeight(request.params[1], chainman);
1027 }
1028
1029 if (index_requested && g_coin_stats_index) {
1030 if (!g_coin_stats_index->BlockUntilSyncedToCurrentChain()) {
1031 const IndexSummary summary{g_coin_stats_index->GetSummary()};
1032
1033 // If a specific block was requested and the index has already synced past that height, we can return the
1034 // data already even though the index is not fully synced yet.
1035 if (pindex->nHeight > summary.best_block_height) {
1036 throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to get data because coinstatsindex is still syncing. Current height: %d", summary.best_block_height));
1037 }
1038 }
1039 }
1040
1041 const std::optional<CCoinsStats> maybe_stats = GetUTXOStats(coins_view, *blockman, hash_type, node.rpc_interruption_point, pindex, index_requested);
1042 if (maybe_stats.has_value()) {
1043 const CCoinsStats& stats = maybe_stats.value();
1044 ret.pushKV("height", (int64_t)stats.nHeight);
1045 ret.pushKV("bestblock", stats.hashBlock.GetHex());
1046 ret.pushKV("txouts", (int64_t)stats.nTransactionOutputs);
1047 ret.pushKV("bogosize", (int64_t)stats.nBogoSize);
1048 if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1049 ret.pushKV("hash_serialized_3", stats.hashSerialized.GetHex());
1050 }
1051 if (hash_type == CoinStatsHashType::MUHASH) {
1052 ret.pushKV("muhash", stats.hashSerialized.GetHex());
1053 }
1054 CHECK_NONFATAL(stats.total_amount.has_value());
1055 ret.pushKV("total_amount", ValueFromAmount(stats.total_amount.value()));
1056 if (!stats.index_used) {
1057 ret.pushKV("transactions", static_cast<int64_t>(stats.nTransactions));
1058 ret.pushKV("disk_size", stats.nDiskSize);
1059 } else {
1060 ret.pushKV("total_unspendable_amount", ValueFromAmount(stats.total_unspendable_amount));
1061
1062 CCoinsStats prev_stats{};
1063 if (pindex->nHeight > 0) {
1064 const std::optional<CCoinsStats> maybe_prev_stats = GetUTXOStats(coins_view, *blockman, hash_type, node.rpc_interruption_point, pindex->pprev, index_requested);
1065 if (!maybe_prev_stats) {
1066 throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
1067 }
1068 prev_stats = maybe_prev_stats.value();
1069 }
1070
1071 UniValue block_info(UniValue::VOBJ);
1072 block_info.pushKV("prevout_spent", ValueFromAmount(stats.total_prevout_spent_amount - prev_stats.total_prevout_spent_amount));
1073 block_info.pushKV("coinbase", ValueFromAmount(stats.total_coinbase_amount - prev_stats.total_coinbase_amount));
1074 block_info.pushKV("new_outputs_ex_coinbase", ValueFromAmount(stats.total_new_outputs_ex_coinbase_amount - prev_stats.total_new_outputs_ex_coinbase_amount));
1075 block_info.pushKV("unspendable", ValueFromAmount(stats.total_unspendable_amount - prev_stats.total_unspendable_amount));
1076
1077 UniValue unspendables(UniValue::VOBJ);
1078 unspendables.pushKV("genesis_block", ValueFromAmount(stats.total_unspendables_genesis_block - prev_stats.total_unspendables_genesis_block));
1079 unspendables.pushKV("bip30", ValueFromAmount(stats.total_unspendables_bip30 - prev_stats.total_unspendables_bip30));
1080 unspendables.pushKV("scripts", ValueFromAmount(stats.total_unspendables_scripts - prev_stats.total_unspendables_scripts));
1081 unspendables.pushKV("unclaimed_rewards", ValueFromAmount(stats.total_unspendables_unclaimed_rewards - prev_stats.total_unspendables_unclaimed_rewards));
1082 block_info.pushKV("unspendables", std::move(unspendables));
1083
1084 ret.pushKV("block_info", std::move(block_info));
1085 }
1086 } else {
1087 throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
1088 }
1089 return ret;
1090},
1091 };
1092}
1093
1095{
1096 return RPCHelpMan{"gettxout",
1097 "\nReturns details about an unspent transaction output.\n",
1098 {
1099 {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
1100 {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
1101 {"include_mempool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to include the mempool. Note that an unspent output that is spent in the mempool won't appear."},
1102 },
1103 {
1104 RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "", ""},
1105 RPCResult{"Otherwise", RPCResult::Type::OBJ, "", "", {
1106 {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
1107 {RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
1108 {RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT},
1109 {RPCResult::Type::OBJ, "scriptPubKey", "", {
1110 {RPCResult::Type::STR, "asm", "Disassembly of the output script"},
1111 {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
1112 {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"},
1113 {RPCResult::Type::STR, "type", "The type, eg pubkeyhash"},
1114 {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
1115 }},
1116 {RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
1117 }},
1118 },
1120 "\nGet unspent transactions\n"
1121 + HelpExampleCli("listunspent", "") +
1122 "\nView the details\n"
1123 + HelpExampleCli("gettxout", "\"txid\" 1") +
1124 "\nAs a JSON-RPC call\n"
1125 + HelpExampleRpc("gettxout", "\"txid\", 1")
1126 },
1127 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1128{
1129 NodeContext& node = EnsureAnyNodeContext(request.context);
1131 LOCK(cs_main);
1132
1134
1135 auto hash{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
1136 COutPoint out{hash, request.params[1].getInt<uint32_t>()};
1137 bool fMempool = true;
1138 if (!request.params[2].isNull())
1139 fMempool = request.params[2].get_bool();
1140
1141 Chainstate& active_chainstate = chainman.ActiveChainstate();
1142 CCoinsViewCache* coins_view = &active_chainstate.CoinsTip();
1143
1144 std::optional<Coin> coin;
1145 if (fMempool) {
1146 const CTxMemPool& mempool = EnsureMemPool(node);
1147 LOCK(mempool.cs);
1148 CCoinsViewMemPool view(coins_view, mempool);
1149 if (!mempool.isSpent(out)) coin = view.GetCoin(out);
1150 } else {
1151 coin = coins_view->GetCoin(out);
1152 }
1153 if (!coin) return UniValue::VNULL;
1154
1155 const CBlockIndex* pindex = active_chainstate.m_blockman.LookupBlockIndex(coins_view->GetBestBlock());
1156 ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
1157 if (coin->nHeight == MEMPOOL_HEIGHT) {
1158 ret.pushKV("confirmations", 0);
1159 } else {
1160 ret.pushKV("confirmations", (int64_t)(pindex->nHeight - coin->nHeight + 1));
1161 }
1162 ret.pushKV("value", ValueFromAmount(coin->out.nValue));
1164 ScriptToUniv(coin->out.scriptPubKey, /*out=*/o, /*include_hex=*/true, /*include_address=*/true);
1165 ret.pushKV("scriptPubKey", std::move(o));
1166 ret.pushKV("coinbase", (bool)coin->fCoinBase);
1167
1168 return ret;
1169},
1170 };
1171}
1172
1174{
1175 return RPCHelpMan{"verifychain",
1176 "\nVerifies blockchain database.\n",
1177 {
1178 {"checklevel", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL)},
1179 strprintf("How thorough the block verification is:\n%s", MakeUnorderedList(CHECKLEVEL_DOC))},
1180 {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, 0=all", DEFAULT_CHECKBLOCKS)}, "The number of blocks to check."},
1181 },
1182 RPCResult{
1183 RPCResult::Type::BOOL, "", "Verification finished successfully. If false, check debug.log for reason."},
1185 HelpExampleCli("verifychain", "")
1186 + HelpExampleRpc("verifychain", "")
1187 },
1188 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1189{
1190 const int check_level{request.params[0].isNull() ? DEFAULT_CHECKLEVEL : request.params[0].getInt<int>()};
1191 const int check_depth{request.params[1].isNull() ? DEFAULT_CHECKBLOCKS : request.params[1].getInt<int>()};
1192
1193 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1194 LOCK(cs_main);
1195
1196 Chainstate& active_chainstate = chainman.ActiveChainstate();
1197 return CVerifyDB(chainman.GetNotifications()).VerifyDB(
1198 active_chainstate, chainman.GetParams().GetConsensus(), active_chainstate.CoinsTip(), check_level, check_depth) == VerifyDBResult::SUCCESS;
1199},
1200 };
1201}
1202
1203static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const ChainstateManager& chainman, Consensus::BuriedDeployment dep)
1204{
1205 // For buried deployments.
1206
1207 if (!DeploymentEnabled(chainman, dep)) return;
1208
1210 rv.pushKV("type", "buried");
1211 // getdeploymentinfo reports the softfork as active from when the chain height is
1212 // one below the activation height
1213 rv.pushKV("active", DeploymentActiveAfter(blockindex, chainman, dep));
1214 rv.pushKV("height", chainman.GetConsensus().DeploymentHeight(dep));
1215 softforks.pushKV(DeploymentName(dep), std::move(rv));
1216}
1217
1218static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const ChainstateManager& chainman, Consensus::DeploymentPos id)
1219{
1220 // For BIP9 deployments.
1221
1222 if (!DeploymentEnabled(chainman, id)) return;
1223 if (blockindex == nullptr) return;
1224
1225 auto get_state_name = [](const ThresholdState state) -> std::string {
1226 switch (state) {
1227 case ThresholdState::DEFINED: return "defined";
1228 case ThresholdState::STARTED: return "started";
1229 case ThresholdState::LOCKED_IN: return "locked_in";
1230 case ThresholdState::ACTIVE: return "active";
1231 case ThresholdState::FAILED: return "failed";
1232 }
1233 return "invalid";
1234 };
1235
1237
1238 const ThresholdState next_state = chainman.m_versionbitscache.State(blockindex, chainman.GetConsensus(), id);
1239 const ThresholdState current_state = chainman.m_versionbitscache.State(blockindex->pprev, chainman.GetConsensus(), id);
1240
1241 const bool has_signal = (ThresholdState::STARTED == current_state || ThresholdState::LOCKED_IN == current_state);
1242
1243 // BIP9 parameters
1244 if (has_signal) {
1245 bip9.pushKV("bit", chainman.GetConsensus().vDeployments[id].bit);
1246 }
1247 bip9.pushKV("start_time", chainman.GetConsensus().vDeployments[id].nStartTime);
1248 bip9.pushKV("timeout", chainman.GetConsensus().vDeployments[id].nTimeout);
1249 bip9.pushKV("min_activation_height", chainman.GetConsensus().vDeployments[id].min_activation_height);
1250
1251 // BIP9 status
1252 bip9.pushKV("status", get_state_name(current_state));
1253 bip9.pushKV("since", chainman.m_versionbitscache.StateSinceHeight(blockindex->pprev, chainman.GetConsensus(), id));
1254 bip9.pushKV("status_next", get_state_name(next_state));
1255
1256 // BIP9 signalling status, if applicable
1257 if (has_signal) {
1258 UniValue statsUV(UniValue::VOBJ);
1259 std::vector<bool> signals;
1260 BIP9Stats statsStruct = chainman.m_versionbitscache.Statistics(blockindex, chainman.GetConsensus(), id, &signals);
1261 statsUV.pushKV("period", statsStruct.period);
1262 statsUV.pushKV("elapsed", statsStruct.elapsed);
1263 statsUV.pushKV("count", statsStruct.count);
1264 if (ThresholdState::LOCKED_IN != current_state) {
1265 statsUV.pushKV("threshold", statsStruct.threshold);
1266 statsUV.pushKV("possible", statsStruct.possible);
1267 }
1268 bip9.pushKV("statistics", std::move(statsUV));
1269
1270 std::string sig;
1271 sig.reserve(signals.size());
1272 for (const bool s : signals) {
1273 sig.push_back(s ? '#' : '-');
1274 }
1275 bip9.pushKV("signalling", sig);
1276 }
1277
1279 rv.pushKV("type", "bip9");
1280 if (ThresholdState::ACTIVE == next_state) {
1281 rv.pushKV("height", chainman.m_versionbitscache.StateSinceHeight(blockindex, chainman.GetConsensus(), id));
1282 }
1283 rv.pushKV("active", ThresholdState::ACTIVE == next_state);
1284 rv.pushKV("bip9", std::move(bip9));
1285
1286 softforks.pushKV(DeploymentName(id), std::move(rv));
1287}
1288
1289// used by rest.cpp:rest_chaininfo, so cannot be static
1291{
1292 return RPCHelpMan{"getblockchaininfo",
1293 "Returns an object containing various state info regarding blockchain processing.\n",
1294 {},
1295 RPCResult{
1296 RPCResult::Type::OBJ, "", "",
1297 {
1298 {RPCResult::Type::STR, "chain", "current network name (" LIST_CHAIN_NAMES ")"},
1299 {RPCResult::Type::NUM, "blocks", "the height of the most-work fully-validated chain. The genesis block has height 0"},
1300 {RPCResult::Type::NUM, "headers", "the current number of headers we have validated"},
1301 {RPCResult::Type::STR, "bestblockhash", "the hash of the currently best block"},
1302 {RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},
1303 {RPCResult::Type::STR_HEX, "target", "The difficulty target"},
1304 {RPCResult::Type::NUM, "difficulty", "the current difficulty"},
1305 {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
1306 {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
1307 {RPCResult::Type::NUM, "verificationprogress", "estimate of verification progress [0..1]"},
1308 {RPCResult::Type::BOOL, "initialblockdownload", "(debug information) estimate of whether this node is in Initial Block Download mode"},
1309 {RPCResult::Type::STR_HEX, "chainwork", "total amount of work in active chain, in hexadecimal"},
1310 {RPCResult::Type::NUM, "size_on_disk", "the estimated size of the block and undo files on disk"},
1311 {RPCResult::Type::BOOL, "pruned", "if the blocks are subject to pruning"},
1312 {RPCResult::Type::NUM, "pruneheight", /*optional=*/true, "height of the last block pruned, plus one (only present if pruning is enabled)"},
1313 {RPCResult::Type::BOOL, "automatic_pruning", /*optional=*/true, "whether automatic pruning is enabled (only present if pruning is enabled)"},
1314 {RPCResult::Type::NUM, "prune_target_size", /*optional=*/true, "the target size used by pruning (only present if automatic pruning is enabled)"},
1315 {RPCResult::Type::STR_HEX, "signet_challenge", /*optional=*/true, "the block challenge (aka. block script), in hexadecimal (only present if the current network is a signet)"},
1316 (IsDeprecatedRPCEnabled("warnings") ?
1317 RPCResult{RPCResult::Type::STR, "warnings", "any network and blockchain warnings (DEPRECATED)"} :
1318 RPCResult{RPCResult::Type::ARR, "warnings", "any network and blockchain warnings (run with `-deprecatedrpc=warnings` to return the latest warning as a single string)",
1319 {
1320 {RPCResult::Type::STR, "", "warning"},
1321 }
1322 }
1323 ),
1324 }},
1326 HelpExampleCli("getblockchaininfo", "")
1327 + HelpExampleRpc("getblockchaininfo", "")
1328 },
1329 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1330{
1331 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1332 LOCK(cs_main);
1333 Chainstate& active_chainstate = chainman.ActiveChainstate();
1334
1335 const CBlockIndex& tip{*CHECK_NONFATAL(active_chainstate.m_chain.Tip())};
1336 const int height{tip.nHeight};
1338 obj.pushKV("chain", chainman.GetParams().GetChainTypeString());
1339 obj.pushKV("blocks", height);
1340 obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
1341 obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex());
1342 obj.pushKV("bits", strprintf("%08x", tip.nBits));
1343 obj.pushKV("target", GetTarget(tip, chainman.GetConsensus().powLimit).GetHex());
1344 obj.pushKV("difficulty", GetDifficulty(tip));
1345 obj.pushKV("time", tip.GetBlockTime());
1346 obj.pushKV("mediantime", tip.GetMedianTimePast());
1347 obj.pushKV("verificationprogress", chainman.GuessVerificationProgress(&tip));
1348 obj.pushKV("initialblockdownload", chainman.IsInitialBlockDownload());
1349 obj.pushKV("chainwork", tip.nChainWork.GetHex());
1350 obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage());
1351 obj.pushKV("pruned", chainman.m_blockman.IsPruneMode());
1352 if (chainman.m_blockman.IsPruneMode()) {
1353 const auto prune_height{GetPruneHeight(chainman.m_blockman, active_chainstate.m_chain)};
1354 obj.pushKV("pruneheight", prune_height ? prune_height.value() + 1 : 0);
1355
1356 const bool automatic_pruning{chainman.m_blockman.GetPruneTarget() != BlockManager::PRUNE_TARGET_MANUAL};
1357 obj.pushKV("automatic_pruning", automatic_pruning);
1358 if (automatic_pruning) {
1359 obj.pushKV("prune_target_size", chainman.m_blockman.GetPruneTarget());
1360 }
1361 }
1362 if (chainman.GetParams().GetChainType() == ChainType::SIGNET) {
1363 const std::vector<uint8_t>& signet_challenge =
1365 obj.pushKV("signet_challenge", HexStr(signet_challenge));
1366 }
1367
1368 NodeContext& node = EnsureAnyNodeContext(request.context);
1369 obj.pushKV("warnings", node::GetWarningsForRpc(*CHECK_NONFATAL(node.warnings), IsDeprecatedRPCEnabled("warnings")));
1370 return obj;
1371},
1372 };
1373}
1374
1375namespace {
1376const std::vector<RPCResult> RPCHelpForDeployment{
1377 {RPCResult::Type::STR, "type", "one of \"buried\", \"bip9\""},
1378 {RPCResult::Type::NUM, "height", /*optional=*/true, "height of the first block which the rules are or will be enforced (only for \"buried\" type, or \"bip9\" type with \"active\" status)"},
1379 {RPCResult::Type::BOOL, "active", "true if the rules are enforced for the mempool and the next block"},
1380 {RPCResult::Type::OBJ, "bip9", /*optional=*/true, "status of bip9 softforks (only for \"bip9\" type)",
1381 {
1382 {RPCResult::Type::NUM, "bit", /*optional=*/true, "the bit (0-28) in the block version field used to signal this softfork (only for \"started\" and \"locked_in\" status)"},
1383 {RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"},
1384 {RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"},
1385 {RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"},
1386 {RPCResult::Type::STR, "status", "status of deployment at specified block (one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\")"},
1387 {RPCResult::Type::NUM, "since", "height of the first block to which the status applies"},
1388 {RPCResult::Type::STR, "status_next", "status of deployment at the next block"},
1389 {RPCResult::Type::OBJ, "statistics", /*optional=*/true, "numeric statistics about signalling for a softfork (only for \"started\" and \"locked_in\" status)",
1390 {
1391 {RPCResult::Type::NUM, "period", "the length in blocks of the signalling period"},
1392 {RPCResult::Type::NUM, "threshold", /*optional=*/true, "the number of blocks with the version bit set required to activate the feature (only for \"started\" status)"},
1393 {RPCResult::Type::NUM, "elapsed", "the number of blocks elapsed since the beginning of the current period"},
1394 {RPCResult::Type::NUM, "count", "the number of blocks with the version bit set in the current period"},
1395 {RPCResult::Type::BOOL, "possible", /*optional=*/true, "returns false if there are not enough blocks left in this period to pass activation threshold (only for \"started\" status)"},
1396 }},
1397 {RPCResult::Type::STR, "signalling", /*optional=*/true, "indicates blocks that signalled with a # and blocks that did not with a -"},
1398 }},
1399};
1400
1401UniValue DeploymentInfo(const CBlockIndex* blockindex, const ChainstateManager& chainman)
1402{
1403 UniValue softforks(UniValue::VOBJ);
1404 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_HEIGHTINCB);
1405 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_DERSIG);
1406 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_CLTV);
1407 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_CSV);
1408 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_SEGWIT);
1409 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TESTDUMMY);
1410 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TAPROOT);
1411 return softforks;
1412}
1413} // anon namespace
1414
1416{
1417 return RPCHelpMan{"getdeploymentinfo",
1418 "Returns an object containing various state info regarding deployments of consensus changes.",
1419 {
1420 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Default{"hash of current chain tip"}, "The block hash at which to query deployment state"},
1421 },
1422 RPCResult{
1423 RPCResult::Type::OBJ, "", "", {
1424 {RPCResult::Type::STR, "hash", "requested block hash (or tip)"},
1425 {RPCResult::Type::NUM, "height", "requested block height (or tip)"},
1426 {RPCResult::Type::OBJ_DYN, "deployments", "", {
1427 {RPCResult::Type::OBJ, "xxxx", "name of the deployment", RPCHelpForDeployment}
1428 }},
1429 }
1430 },
1431 RPCExamples{ HelpExampleCli("getdeploymentinfo", "") + HelpExampleRpc("getdeploymentinfo", "") },
1432 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1433 {
1434 const ChainstateManager& chainman = EnsureAnyChainman(request.context);
1435 LOCK(cs_main);
1436 const Chainstate& active_chainstate = chainman.ActiveChainstate();
1437
1438 const CBlockIndex* blockindex;
1439 if (request.params[0].isNull()) {
1440 blockindex = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
1441 } else {
1442 const uint256 hash(ParseHashV(request.params[0], "blockhash"));
1443 blockindex = chainman.m_blockman.LookupBlockIndex(hash);
1444 if (!blockindex) {
1445 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1446 }
1447 }
1448
1449 UniValue deploymentinfo(UniValue::VOBJ);
1450 deploymentinfo.pushKV("hash", blockindex->GetBlockHash().ToString());
1451 deploymentinfo.pushKV("height", blockindex->nHeight);
1452 deploymentinfo.pushKV("deployments", DeploymentInfo(blockindex, chainman));
1453 return deploymentinfo;
1454 },
1455 };
1456}
1457
1460{
1461 bool operator()(const CBlockIndex* a, const CBlockIndex* b) const
1462 {
1463 /* Make sure that unequal blocks with the same height do not compare
1464 equal. Use the pointers themselves to make a distinction. */
1465
1466 if (a->nHeight != b->nHeight)
1467 return (a->nHeight > b->nHeight);
1468
1469 return a < b;
1470 }
1471};
1472
1474{
1475 return RPCHelpMan{"getchaintips",
1476 "Return information about all known tips in the block tree,"
1477 " including the main chain as well as orphaned branches.\n",
1478 {},
1479 RPCResult{
1480 RPCResult::Type::ARR, "", "",
1481 {{RPCResult::Type::OBJ, "", "",
1482 {
1483 {RPCResult::Type::NUM, "height", "height of the chain tip"},
1484 {RPCResult::Type::STR_HEX, "hash", "block hash of the tip"},
1485 {RPCResult::Type::NUM, "branchlen", "zero for main chain, otherwise length of branch connecting the tip to the main chain"},
1486 {RPCResult::Type::STR, "status", "status of the chain, \"active\" for the main chain\n"
1487 "Possible values for status:\n"
1488 "1. \"invalid\" This branch contains at least one invalid block\n"
1489 "2. \"headers-only\" Not all blocks for this branch are available, but the headers are valid\n"
1490 "3. \"valid-headers\" All blocks are available for this branch, but they were never fully validated\n"
1491 "4. \"valid-fork\" This branch is not part of the active chain, but is fully validated\n"
1492 "5. \"active\" This is the tip of the active main chain, which is certainly valid"},
1493 }}}},
1495 HelpExampleCli("getchaintips", "")
1496 + HelpExampleRpc("getchaintips", "")
1497 },
1498 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1499{
1500 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1501 LOCK(cs_main);
1502 CChain& active_chain = chainman.ActiveChain();
1503
1504 /*
1505 * Idea: The set of chain tips is the active chain tip, plus orphan blocks which do not have another orphan building off of them.
1506 * Algorithm:
1507 * - Make one pass through BlockIndex(), picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers.
1508 * - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip.
1509 * - Add the active chain tip
1510 */
1511 std::set<const CBlockIndex*, CompareBlocksByHeight> setTips;
1512 std::set<const CBlockIndex*> setOrphans;
1513 std::set<const CBlockIndex*> setPrevs;
1514
1515 for (const auto& [_, block_index] : chainman.BlockIndex()) {
1516 if (!active_chain.Contains(&block_index)) {
1517 setOrphans.insert(&block_index);
1518 setPrevs.insert(block_index.pprev);
1519 }
1520 }
1521
1522 for (std::set<const CBlockIndex*>::iterator it = setOrphans.begin(); it != setOrphans.end(); ++it) {
1523 if (setPrevs.erase(*it) == 0) {
1524 setTips.insert(*it);
1525 }
1526 }
1527
1528 // Always report the currently active tip.
1529 setTips.insert(active_chain.Tip());
1530
1531 /* Construct the output array. */
1533 for (const CBlockIndex* block : setTips) {
1535 obj.pushKV("height", block->nHeight);
1536 obj.pushKV("hash", block->phashBlock->GetHex());
1537
1538 const int branchLen = block->nHeight - active_chain.FindFork(block)->nHeight;
1539 obj.pushKV("branchlen", branchLen);
1540
1541 std::string status;
1542 if (active_chain.Contains(block)) {
1543 // This block is part of the currently active chain.
1544 status = "active";
1545 } else if (block->nStatus & BLOCK_FAILED_MASK) {
1546 // This block or one of its ancestors is invalid.
1547 status = "invalid";
1548 } else if (!block->HaveNumChainTxs()) {
1549 // This block cannot be connected because full block data for it or one of its parents is missing.
1550 status = "headers-only";
1551 } else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {
1552 // This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.
1553 status = "valid-fork";
1554 } else if (block->IsValid(BLOCK_VALID_TREE)) {
1555 // The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.
1556 status = "valid-headers";
1557 } else {
1558 // No clue.
1559 status = "unknown";
1560 }
1561 obj.pushKV("status", status);
1562
1563 res.push_back(std::move(obj));
1564 }
1565
1566 return res;
1567},
1568 };
1569}
1570
1572{
1573 return RPCHelpMan{"preciousblock",
1574 "\nTreats a block as if it were received before others with the same work.\n"
1575 "\nA later preciousblock call can override the effect of an earlier one.\n"
1576 "\nThe effects of preciousblock are not retained across restarts.\n",
1577 {
1578 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as precious"},
1579 },
1582 HelpExampleCli("preciousblock", "\"blockhash\"")
1583 + HelpExampleRpc("preciousblock", "\"blockhash\"")
1584 },
1585 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1586{
1587 uint256 hash(ParseHashV(request.params[0], "blockhash"));
1588 CBlockIndex* pblockindex;
1589
1590 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1591 {
1592 LOCK(cs_main);
1593 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1594 if (!pblockindex) {
1595 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1596 }
1597 }
1598
1600 chainman.ActiveChainstate().PreciousBlock(state, pblockindex);
1601
1602 if (!state.IsValid()) {
1604 }
1605
1606 return UniValue::VNULL;
1607},
1608 };
1609}
1610
1611void InvalidateBlock(ChainstateManager& chainman, const uint256 block_hash) {
1613 CBlockIndex* pblockindex;
1614 {
1615 LOCK(chainman.GetMutex());
1616 pblockindex = chainman.m_blockman.LookupBlockIndex(block_hash);
1617 if (!pblockindex) {
1618 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1619 }
1620 }
1621 chainman.ActiveChainstate().InvalidateBlock(state, pblockindex);
1622
1623 if (state.IsValid()) {
1624 chainman.ActiveChainstate().ActivateBestChain(state);
1625 }
1626
1627 if (!state.IsValid()) {
1629 }
1630}
1631
1633{
1634 return RPCHelpMan{"invalidateblock",
1635 "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n",
1636 {
1637 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as invalid"},
1638 },
1641 HelpExampleCli("invalidateblock", "\"blockhash\"")
1642 + HelpExampleRpc("invalidateblock", "\"blockhash\"")
1643 },
1644 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1645{
1646 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1647 uint256 hash(ParseHashV(request.params[0], "blockhash"));
1648
1649 InvalidateBlock(chainman, hash);
1650
1651 return UniValue::VNULL;
1652},
1653 };
1654}
1655
1656void ReconsiderBlock(ChainstateManager& chainman, uint256 block_hash) {
1657 {
1658 LOCK(chainman.GetMutex());
1659 CBlockIndex* pblockindex = chainman.m_blockman.LookupBlockIndex(block_hash);
1660 if (!pblockindex) {
1661 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1662 }
1663
1664 chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex);
1665 chainman.RecalculateBestHeader();
1666 }
1667
1669 chainman.ActiveChainstate().ActivateBestChain(state);
1670
1671 if (!state.IsValid()) {
1673 }
1674}
1675
1677{
1678 return RPCHelpMan{"reconsiderblock",
1679 "\nRemoves invalidity status of a block, its ancestors and its descendants, reconsider them for activation.\n"
1680 "This can be used to undo the effects of invalidateblock.\n",
1681 {
1682 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to reconsider"},
1683 },
1686 HelpExampleCli("reconsiderblock", "\"blockhash\"")
1687 + HelpExampleRpc("reconsiderblock", "\"blockhash\"")
1688 },
1689 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1690{
1691 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1692 uint256 hash(ParseHashV(request.params[0], "blockhash"));
1693
1694 ReconsiderBlock(chainman, hash);
1695
1696 return UniValue::VNULL;
1697},
1698 };
1699}
1700
1702{
1703 return RPCHelpMan{"getchaintxstats",
1704 "\nCompute statistics about the total number and rate of transactions in the chain.\n",
1705 {
1706 {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{"one month"}, "Size of the window in number of blocks"},
1707 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"chain tip"}, "The hash of the block that ends the window."},
1708 },
1709 RPCResult{
1710 RPCResult::Type::OBJ, "", "",
1711 {
1712 {RPCResult::Type::NUM_TIME, "time", "The timestamp for the final block in the window, expressed in " + UNIX_EPOCH_TIME},
1713 {RPCResult::Type::NUM, "txcount", /*optional=*/true,
1714 "The total number of transactions in the chain up to that point, if known. "
1715 "It may be unknown when using assumeutxo."},
1716 {RPCResult::Type::STR_HEX, "window_final_block_hash", "The hash of the final block in the window"},
1717 {RPCResult::Type::NUM, "window_final_block_height", "The height of the final block in the window."},
1718 {RPCResult::Type::NUM, "window_block_count", "Size of the window in number of blocks"},
1719 {RPCResult::Type::NUM, "window_interval", /*optional=*/true, "The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0"},
1720 {RPCResult::Type::NUM, "window_tx_count", /*optional=*/true,
1721 "The number of transactions in the window. "
1722 "Only returned if \"window_block_count\" is > 0 and if txcount exists for the start and end of the window."},
1723 {RPCResult::Type::NUM, "txrate", /*optional=*/true,
1724 "The average rate of transactions per second in the window. "
1725 "Only returned if \"window_interval\" is > 0 and if window_tx_count exists."},
1726 }},
1728 HelpExampleCli("getchaintxstats", "")
1729 + HelpExampleRpc("getchaintxstats", "2016")
1730 },
1731 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1732{
1733 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1734 const CBlockIndex* pindex;
1735 int blockcount = 30 * 24 * 60 * 60 / chainman.GetParams().GetConsensus().nPowTargetSpacing; // By default: 1 month
1736
1737 if (request.params[1].isNull()) {
1738 LOCK(cs_main);
1739 pindex = chainman.ActiveChain().Tip();
1740 } else {
1741 uint256 hash(ParseHashV(request.params[1], "blockhash"));
1742 LOCK(cs_main);
1743 pindex = chainman.m_blockman.LookupBlockIndex(hash);
1744 if (!pindex) {
1745 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1746 }
1747 if (!chainman.ActiveChain().Contains(pindex)) {
1748 throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain");
1749 }
1750 }
1751
1752 CHECK_NONFATAL(pindex != nullptr);
1753
1754 if (request.params[0].isNull()) {
1755 blockcount = std::max(0, std::min(blockcount, pindex->nHeight - 1));
1756 } else {
1757 blockcount = request.params[0].getInt<int>();
1758
1759 if (blockcount < 0 || (blockcount > 0 && blockcount >= pindex->nHeight)) {
1760 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 0 and the block's height - 1");
1761 }
1762 }
1763
1764 const CBlockIndex& past_block{*CHECK_NONFATAL(pindex->GetAncestor(pindex->nHeight - blockcount))};
1765 const int64_t nTimeDiff{pindex->GetMedianTimePast() - past_block.GetMedianTimePast()};
1766
1768 ret.pushKV("time", (int64_t)pindex->nTime);
1769 if (pindex->m_chain_tx_count) {
1770 ret.pushKV("txcount", pindex->m_chain_tx_count);
1771 }
1772 ret.pushKV("window_final_block_hash", pindex->GetBlockHash().GetHex());
1773 ret.pushKV("window_final_block_height", pindex->nHeight);
1774 ret.pushKV("window_block_count", blockcount);
1775 if (blockcount > 0) {
1776 ret.pushKV("window_interval", nTimeDiff);
1777 if (pindex->m_chain_tx_count != 0 && past_block.m_chain_tx_count != 0) {
1778 const auto window_tx_count = pindex->m_chain_tx_count - past_block.m_chain_tx_count;
1779 ret.pushKV("window_tx_count", window_tx_count);
1780 if (nTimeDiff > 0) {
1781 ret.pushKV("txrate", double(window_tx_count) / nTimeDiff);
1782 }
1783 }
1784 }
1785
1786 return ret;
1787},
1788 };
1789}
1790
1791template<typename T>
1792static T CalculateTruncatedMedian(std::vector<T>& scores)
1793{
1794 size_t size = scores.size();
1795 if (size == 0) {
1796 return 0;
1797 }
1798
1799 std::sort(scores.begin(), scores.end());
1800 if (size % 2 == 0) {
1801 return (scores[size / 2 - 1] + scores[size / 2]) / 2;
1802 } else {
1803 return scores[size / 2];
1804 }
1805}
1806
1807void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight)
1808{
1809 if (scores.empty()) {
1810 return;
1811 }
1812
1813 std::sort(scores.begin(), scores.end());
1814
1815 // 10th, 25th, 50th, 75th, and 90th percentile weight units.
1816 const double weights[NUM_GETBLOCKSTATS_PERCENTILES] = {
1817 total_weight / 10.0, total_weight / 4.0, total_weight / 2.0, (total_weight * 3.0) / 4.0, (total_weight * 9.0) / 10.0
1818 };
1819
1820 int64_t next_percentile_index = 0;
1821 int64_t cumulative_weight = 0;
1822 for (const auto& element : scores) {
1823 cumulative_weight += element.second;
1824 while (next_percentile_index < NUM_GETBLOCKSTATS_PERCENTILES && cumulative_weight >= weights[next_percentile_index]) {
1825 result[next_percentile_index] = element.first;
1826 ++next_percentile_index;
1827 }
1828 }
1829
1830 // Fill any remaining percentiles with the last value.
1831 for (int64_t i = next_percentile_index; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {
1832 result[i] = scores.back().first;
1833 }
1834}
1835
1836template<typename T>
1837static inline bool SetHasKeys(const std::set<T>& set) {return false;}
1838template<typename T, typename Tk, typename... Args>
1839static inline bool SetHasKeys(const std::set<T>& set, const Tk& key, const Args&... args)
1840{
1841 return (set.count(key) != 0) || SetHasKeys(set, args...);
1842}
1843
1844// outpoint (needed for the utxo index) + nHeight + fCoinBase
1845static constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);
1846
1848{
1849 return RPCHelpMan{"getblockstats",
1850 "\nCompute per block statistics for a given window. All amounts are in satoshis.\n"
1851 "It won't work for some heights with pruning.\n",
1852 {
1853 {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block",
1855 .skip_type_check = true,
1856 .type_str = {"", "string or numeric"},
1857 }},
1858 {"stats", RPCArg::Type::ARR, RPCArg::DefaultHint{"all values"}, "Values to plot (see result below)",
1859 {
1860 {"height", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
1861 {"time", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
1862 },
1864 },
1865 RPCResult{
1866 RPCResult::Type::OBJ, "", "",
1867 {
1868 {RPCResult::Type::NUM, "avgfee", /*optional=*/true, "Average fee in the block"},
1869 {RPCResult::Type::NUM, "avgfeerate", /*optional=*/true, "Average feerate (in satoshis per virtual byte)"},
1870 {RPCResult::Type::NUM, "avgtxsize", /*optional=*/true, "Average transaction size"},
1871 {RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "The block hash (to check for potential reorgs)"},
1872 {RPCResult::Type::ARR_FIXED, "feerate_percentiles", /*optional=*/true, "Feerates at the 10th, 25th, 50th, 75th, and 90th percentile weight unit (in satoshis per virtual byte)",
1873 {
1874 {RPCResult::Type::NUM, "10th_percentile_feerate", "The 10th percentile feerate"},
1875 {RPCResult::Type::NUM, "25th_percentile_feerate", "The 25th percentile feerate"},
1876 {RPCResult::Type::NUM, "50th_percentile_feerate", "The 50th percentile feerate"},
1877 {RPCResult::Type::NUM, "75th_percentile_feerate", "The 75th percentile feerate"},
1878 {RPCResult::Type::NUM, "90th_percentile_feerate", "The 90th percentile feerate"},
1879 }},
1880 {RPCResult::Type::NUM, "height", /*optional=*/true, "The height of the block"},
1881 {RPCResult::Type::NUM, "ins", /*optional=*/true, "The number of inputs (excluding coinbase)"},
1882 {RPCResult::Type::NUM, "maxfee", /*optional=*/true, "Maximum fee in the block"},
1883 {RPCResult::Type::NUM, "maxfeerate", /*optional=*/true, "Maximum feerate (in satoshis per virtual byte)"},
1884 {RPCResult::Type::NUM, "maxtxsize", /*optional=*/true, "Maximum transaction size"},
1885 {RPCResult::Type::NUM, "medianfee", /*optional=*/true, "Truncated median fee in the block"},
1886 {RPCResult::Type::NUM, "mediantime", /*optional=*/true, "The block median time past"},
1887 {RPCResult::Type::NUM, "mediantxsize", /*optional=*/true, "Truncated median transaction size"},
1888 {RPCResult::Type::NUM, "minfee", /*optional=*/true, "Minimum fee in the block"},
1889 {RPCResult::Type::NUM, "minfeerate", /*optional=*/true, "Minimum feerate (in satoshis per virtual byte)"},
1890 {RPCResult::Type::NUM, "mintxsize", /*optional=*/true, "Minimum transaction size"},
1891 {RPCResult::Type::NUM, "outs", /*optional=*/true, "The number of outputs"},
1892 {RPCResult::Type::NUM, "subsidy", /*optional=*/true, "The block subsidy"},
1893 {RPCResult::Type::NUM, "swtotal_size", /*optional=*/true, "Total size of all segwit transactions"},
1894 {RPCResult::Type::NUM, "swtotal_weight", /*optional=*/true, "Total weight of all segwit transactions"},
1895 {RPCResult::Type::NUM, "swtxs", /*optional=*/true, "The number of segwit transactions"},
1896 {RPCResult::Type::NUM, "time", /*optional=*/true, "The block time"},
1897 {RPCResult::Type::NUM, "total_out", /*optional=*/true, "Total amount in all outputs (excluding coinbase and thus reward [ie subsidy + totalfee])"},
1898 {RPCResult::Type::NUM, "total_size", /*optional=*/true, "Total size of all non-coinbase transactions"},
1899 {RPCResult::Type::NUM, "total_weight", /*optional=*/true, "Total weight of all non-coinbase transactions"},
1900 {RPCResult::Type::NUM, "totalfee", /*optional=*/true, "The fee total"},
1901 {RPCResult::Type::NUM, "txs", /*optional=*/true, "The number of transactions (including coinbase)"},
1902 {RPCResult::Type::NUM, "utxo_increase", /*optional=*/true, "The increase/decrease in the number of unspent outputs (not discounting op_return and similar)"},
1903 {RPCResult::Type::NUM, "utxo_size_inc", /*optional=*/true, "The increase/decrease in size for the utxo index (not discounting op_return and similar)"},
1904 {RPCResult::Type::NUM, "utxo_increase_actual", /*optional=*/true, "The increase/decrease in the number of unspent outputs, not counting unspendables"},
1905 {RPCResult::Type::NUM, "utxo_size_inc_actual", /*optional=*/true, "The increase/decrease in size for the utxo index, not counting unspendables"},
1906 }},
1908 HelpExampleCli("getblockstats", R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
1909 HelpExampleCli("getblockstats", R"(1000 '["minfeerate","avgfeerate"]')") +
1910 HelpExampleRpc("getblockstats", R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") +
1911 HelpExampleRpc("getblockstats", R"(1000, ["minfeerate","avgfeerate"])")
1912 },
1913 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1914{
1915 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1916 const CBlockIndex& pindex{*CHECK_NONFATAL(ParseHashOrHeight(request.params[0], chainman))};
1917
1918 std::set<std::string> stats;
1919 if (!request.params[1].isNull()) {
1920 const UniValue stats_univalue = request.params[1].get_array();
1921 for (unsigned int i = 0; i < stats_univalue.size(); i++) {
1922 const std::string stat = stats_univalue[i].get_str();
1923 stats.insert(stat);
1924 }
1925 }
1926
1927 const CBlock& block = GetBlockChecked(chainman.m_blockman, pindex);
1928 const CBlockUndo& blockUndo = GetUndoChecked(chainman.m_blockman, pindex);
1929
1930 const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default)
1931 const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0;
1932 const bool do_medianfee = do_all || stats.count("medianfee") != 0;
1933 const bool do_feerate_percentiles = do_all || stats.count("feerate_percentiles") != 0;
1934 const bool loop_inputs = do_all || do_medianfee || do_feerate_percentiles ||
1935 SetHasKeys(stats, "utxo_increase", "utxo_increase_actual", "utxo_size_inc", "utxo_size_inc_actual", "totalfee", "avgfee", "avgfeerate", "minfee", "maxfee", "minfeerate", "maxfeerate");
1936 const bool loop_outputs = do_all || loop_inputs || stats.count("total_out");
1937 const bool do_calculate_size = do_mediantxsize ||
1938 SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize", "maxtxsize", "swtotal_size");
1939 const bool do_calculate_weight = do_all || SetHasKeys(stats, "total_weight", "avgfeerate", "swtotal_weight", "avgfeerate", "feerate_percentiles", "minfeerate", "maxfeerate");
1940 const bool do_calculate_sw = do_all || SetHasKeys(stats, "swtxs", "swtotal_size", "swtotal_weight");
1941
1942 CAmount maxfee = 0;
1943 CAmount maxfeerate = 0;
1944 CAmount minfee = MAX_MONEY;
1945 CAmount minfeerate = MAX_MONEY;
1946 CAmount total_out = 0;
1947 CAmount totalfee = 0;
1948 int64_t inputs = 0;
1949 int64_t maxtxsize = 0;
1950 int64_t mintxsize = MAX_BLOCK_SERIALIZED_SIZE;
1951 int64_t outputs = 0;
1952 int64_t swtotal_size = 0;
1953 int64_t swtotal_weight = 0;
1954 int64_t swtxs = 0;
1955 int64_t total_size = 0;
1956 int64_t total_weight = 0;
1957 int64_t utxos = 0;
1958 int64_t utxo_size_inc = 0;
1959 int64_t utxo_size_inc_actual = 0;
1960 std::vector<CAmount> fee_array;
1961 std::vector<std::pair<CAmount, int64_t>> feerate_array;
1962 std::vector<int64_t> txsize_array;
1963
1964 for (size_t i = 0; i < block.vtx.size(); ++i) {
1965 const auto& tx = block.vtx.at(i);
1966 outputs += tx->vout.size();
1967
1968 CAmount tx_total_out = 0;
1969 if (loop_outputs) {
1970 for (const CTxOut& out : tx->vout) {
1971 tx_total_out += out.nValue;
1972
1973 size_t out_size = GetSerializeSize(out) + PER_UTXO_OVERHEAD;
1974 utxo_size_inc += out_size;
1975
1976 // The Genesis block and the repeated BIP30 block coinbases don't change the UTXO
1977 // set counts, so they have to be excluded from the statistics
1978 if (pindex.nHeight == 0 || (IsBIP30Repeat(pindex) && tx->IsCoinBase())) continue;
1979 // Skip unspendable outputs since they are not included in the UTXO set
1980 if (out.scriptPubKey.IsUnspendable()) continue;
1981
1982 ++utxos;
1983 utxo_size_inc_actual += out_size;
1984 }
1985 }
1986
1987 if (tx->IsCoinBase()) {
1988 continue;
1989 }
1990
1991 inputs += tx->vin.size(); // Don't count coinbase's fake input
1992 total_out += tx_total_out; // Don't count coinbase reward
1993
1994 int64_t tx_size = 0;
1995 if (do_calculate_size) {
1996
1997 tx_size = tx->GetTotalSize();
1998 if (do_mediantxsize) {
1999 txsize_array.push_back(tx_size);
2000 }
2001 maxtxsize = std::max(maxtxsize, tx_size);
2002 mintxsize = std::min(mintxsize, tx_size);
2003 total_size += tx_size;
2004 }
2005
2006 int64_t weight = 0;
2007 if (do_calculate_weight) {
2008 weight = GetTransactionWeight(*tx);
2009 total_weight += weight;
2010 }
2011
2012 if (do_calculate_sw && tx->HasWitness()) {
2013 ++swtxs;
2014 swtotal_size += tx_size;
2015 swtotal_weight += weight;
2016 }
2017
2018 if (loop_inputs) {
2019 CAmount tx_total_in = 0;
2020 const auto& txundo = blockUndo.vtxundo.at(i - 1);
2021 for (const Coin& coin: txundo.vprevout) {
2022 const CTxOut& prevoutput = coin.out;
2023
2024 tx_total_in += prevoutput.nValue;
2025 size_t prevout_size = GetSerializeSize(prevoutput) + PER_UTXO_OVERHEAD;
2026 utxo_size_inc -= prevout_size;
2027 utxo_size_inc_actual -= prevout_size;
2028 }
2029
2030 CAmount txfee = tx_total_in - tx_total_out;
2031 CHECK_NONFATAL(MoneyRange(txfee));
2032 if (do_medianfee) {
2033 fee_array.push_back(txfee);
2034 }
2035 maxfee = std::max(maxfee, txfee);
2036 minfee = std::min(minfee, txfee);
2037 totalfee += txfee;
2038
2039 // New feerate uses satoshis per virtual byte instead of per serialized byte
2040 CAmount feerate = weight ? (txfee * WITNESS_SCALE_FACTOR) / weight : 0;
2041 if (do_feerate_percentiles) {
2042 feerate_array.emplace_back(feerate, weight);
2043 }
2044 maxfeerate = std::max(maxfeerate, feerate);
2045 minfeerate = std::min(minfeerate, feerate);
2046 }
2047 }
2048
2049 CAmount feerate_percentiles[NUM_GETBLOCKSTATS_PERCENTILES] = { 0 };
2050 CalculatePercentilesByWeight(feerate_percentiles, feerate_array, total_weight);
2051
2052 UniValue feerates_res(UniValue::VARR);
2053 for (int64_t i = 0; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {
2054 feerates_res.push_back(feerate_percentiles[i]);
2055 }
2056
2057 UniValue ret_all(UniValue::VOBJ);
2058 ret_all.pushKV("avgfee", (block.vtx.size() > 1) ? totalfee / (block.vtx.size() - 1) : 0);
2059 ret_all.pushKV("avgfeerate", total_weight ? (totalfee * WITNESS_SCALE_FACTOR) / total_weight : 0); // Unit: sat/vbyte
2060 ret_all.pushKV("avgtxsize", (block.vtx.size() > 1) ? total_size / (block.vtx.size() - 1) : 0);
2061 ret_all.pushKV("blockhash", pindex.GetBlockHash().GetHex());
2062 ret_all.pushKV("feerate_percentiles", std::move(feerates_res));
2063 ret_all.pushKV("height", (int64_t)pindex.nHeight);
2064 ret_all.pushKV("ins", inputs);
2065 ret_all.pushKV("maxfee", maxfee);
2066 ret_all.pushKV("maxfeerate", maxfeerate);
2067 ret_all.pushKV("maxtxsize", maxtxsize);
2068 ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
2069 ret_all.pushKV("mediantime", pindex.GetMedianTimePast());
2070 ret_all.pushKV("mediantxsize", CalculateTruncatedMedian(txsize_array));
2071 ret_all.pushKV("minfee", (minfee == MAX_MONEY) ? 0 : minfee);
2072 ret_all.pushKV("minfeerate", (minfeerate == MAX_MONEY) ? 0 : minfeerate);
2073 ret_all.pushKV("mintxsize", mintxsize == MAX_BLOCK_SERIALIZED_SIZE ? 0 : mintxsize);
2074 ret_all.pushKV("outs", outputs);
2075 ret_all.pushKV("subsidy", GetBlockSubsidy(pindex.nHeight, chainman.GetParams().GetConsensus()));
2076 ret_all.pushKV("swtotal_size", swtotal_size);
2077 ret_all.pushKV("swtotal_weight", swtotal_weight);
2078 ret_all.pushKV("swtxs", swtxs);
2079 ret_all.pushKV("time", pindex.GetBlockTime());
2080 ret_all.pushKV("total_out", total_out);
2081 ret_all.pushKV("total_size", total_size);
2082 ret_all.pushKV("total_weight", total_weight);
2083 ret_all.pushKV("totalfee", totalfee);
2084 ret_all.pushKV("txs", (int64_t)block.vtx.size());
2085 ret_all.pushKV("utxo_increase", outputs - inputs);
2086 ret_all.pushKV("utxo_size_inc", utxo_size_inc);
2087 ret_all.pushKV("utxo_increase_actual", utxos - inputs);
2088 ret_all.pushKV("utxo_size_inc_actual", utxo_size_inc_actual);
2089
2090 if (do_all) {
2091 return ret_all;
2092 }
2093
2095 for (const std::string& stat : stats) {
2096 const UniValue& value = ret_all[stat];
2097 if (value.isNull()) {
2098 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid selected statistic '%s'", stat));
2099 }
2100 ret.pushKV(stat, value);
2101 }
2102 return ret;
2103},
2104 };
2105}
2106
2107namespace {
2109bool 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)
2110{
2111 scan_progress = 0;
2112 count = 0;
2113 while (cursor->Valid()) {
2114 COutPoint key;
2115 Coin coin;
2116 if (!cursor->GetKey(key) || !cursor->GetValue(coin)) return false;
2117 if (++count % 8192 == 0) {
2118 interruption_point();
2119 if (should_abort) {
2120 // allow to abort the scan via the abort reference
2121 return false;
2122 }
2123 }
2124 if (count % 256 == 0) {
2125 // update progress reference every 256 item
2126 uint32_t high = 0x100 * *UCharCast(key.hash.begin()) + *(UCharCast(key.hash.begin()) + 1);
2127 scan_progress = (int)(high * 100.0 / 65536.0 + 0.5);
2128 }
2129 if (needles.count(coin.out.scriptPubKey)) {
2130 out_results.emplace(key, coin);
2131 }
2132 cursor->Next();
2133 }
2134 scan_progress = 100;
2135 return true;
2136}
2137} // namespace
2138
2140static std::atomic<int> g_scan_progress;
2141static std::atomic<bool> g_scan_in_progress;
2142static std::atomic<bool> g_should_abort_scan;
2144{
2145private:
2146 bool m_could_reserve{false};
2147public:
2148 explicit CoinsViewScanReserver() = default;
2149
2150 bool reserve() {
2152 if (g_scan_in_progress.exchange(true)) {
2153 return false;
2154 }
2156 m_could_reserve = true;
2157 return true;
2158 }
2159
2161 if (m_could_reserve) {
2162 g_scan_in_progress = false;
2163 g_scan_progress = 0;
2164 }
2165 }
2166};
2167
2168static const auto scan_action_arg_desc = RPCArg{
2169 "action", RPCArg::Type::STR, RPCArg::Optional::NO, "The action to execute\n"
2170 "\"start\" for starting a scan\n"
2171 "\"abort\" for aborting the current scan (returns true when abort was successful)\n"
2172 "\"status\" for progress report (in %) of the current scan"
2173};
2174
2175static const auto scan_objects_arg_desc = RPCArg{
2176 "scanobjects", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "Array of scan objects. Required for \"start\" action\n"
2177 "Every scan object is either a string descriptor or an object:",
2178 {
2179 {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
2180 {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with output descriptor and metadata",
2181 {
2182 {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
2183 {"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "The range of HD chain indexes to explore (either end or [begin,end])"},
2184 }},
2185 },
2186 RPCArgOptions{.oneline_description="[scanobjects,...]"},
2187};
2188
2189static const auto scan_result_abort = RPCResult{
2190 "when action=='abort'", RPCResult::Type::BOOL, "success",
2191 "True if scan will be aborted (not necessarily before this RPC returns), or false if there is no scan to abort"
2192};
2194 "when action=='status' and no scan is in progress - possibly already completed", RPCResult::Type::NONE, "", ""
2195};
2197 "when action=='status' and a scan is currently in progress", RPCResult::Type::OBJ, "", "",
2198 {{RPCResult::Type::NUM, "progress", "Approximate percent complete"},}
2199};
2200
2201
2203{
2204 // raw() descriptor corresponding to mainnet address 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S
2205 const std::string EXAMPLE_DESCRIPTOR_RAW = "raw(76a91411b366edfc0a8b66feebae5c2e25a7b6a5d1cf3188ac)#fm24fxxy";
2206
2207 return RPCHelpMan{"scantxoutset",
2208 "\nScans the unspent transaction output set for entries that match certain output descriptors.\n"
2209 "Examples of output descriptors are:\n"
2210 " addr(<address>) Outputs whose output script corresponds to the specified address (does not include P2PK)\n"
2211 " raw(<hex script>) Outputs whose output script equals the specified hex-encoded bytes\n"
2212 " combo(<pubkey>) P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH outputs for the given pubkey\n"
2213 " pkh(<pubkey>) P2PKH outputs for the given pubkey\n"
2214 " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n"
2215 " tr(<pubkey>) P2TR\n"
2216 " tr(<pubkey>,{pk(<pubkey>)}) P2TR with single fallback pubkey in tapscript\n"
2217 " rawtr(<pubkey>) P2TR with the specified key as output key rather than inner\n"
2218 " wsh(and_v(v:pk(<pubkey>),after(2))) P2WSH miniscript with mandatory pubkey and a timelock\n"
2219 "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
2220 "or more path elements separated by \"/\", and optionally ending in \"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
2221 "unhardened or hardened child keys.\n"
2222 "In the latter case, a range needs to be specified by below if different from 1000.\n"
2223 "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n",
2224 {
2227 },
2228 {
2229 RPCResult{"when action=='start'; only returns after scan completes", RPCResult::Type::OBJ, "", "", {
2230 {RPCResult::Type::BOOL, "success", "Whether the scan was completed"},
2231 {RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs scanned"},
2232 {RPCResult::Type::NUM, "height", "The block height at which the scan was done"},
2233 {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
2234 {RPCResult::Type::ARR, "unspents", "",
2235 {
2236 {RPCResult::Type::OBJ, "", "",
2237 {
2238 {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
2239 {RPCResult::Type::NUM, "vout", "The vout value"},
2240 {RPCResult::Type::STR_HEX, "scriptPubKey", "The output script"},
2241 {RPCResult::Type::STR, "desc", "A specialized descriptor for the matched output script"},
2242 {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the unspent output"},
2243 {RPCResult::Type::BOOL, "coinbase", "Whether this is a coinbase output"},
2244 {RPCResult::Type::NUM, "height", "Height of the unspent transaction output"},
2245 {RPCResult::Type::STR_HEX, "blockhash", "Blockhash of the unspent transaction output"},
2246 {RPCResult::Type::NUM, "confirmations", "Number of confirmations of the unspent transaction output when the scan was done"},
2247 }},
2248 }},
2249 {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of all found unspent outputs in " + CURRENCY_UNIT},
2250 }},
2254 },
2256 HelpExampleCli("scantxoutset", "start \'[\"" + EXAMPLE_DESCRIPTOR_RAW + "\"]\'") +
2257 HelpExampleCli("scantxoutset", "status") +
2258 HelpExampleCli("scantxoutset", "abort") +
2259 HelpExampleRpc("scantxoutset", "\"start\", [\"" + EXAMPLE_DESCRIPTOR_RAW + "\"]") +
2260 HelpExampleRpc("scantxoutset", "\"status\"") +
2261 HelpExampleRpc("scantxoutset", "\"abort\"")
2262 },
2263 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2264{
2265 UniValue result(UniValue::VOBJ);
2266 const auto action{self.Arg<std::string>("action")};
2267 if (action == "status") {
2268 CoinsViewScanReserver reserver;
2269 if (reserver.reserve()) {
2270 // no scan in progress
2271 return UniValue::VNULL;
2272 }
2273 result.pushKV("progress", g_scan_progress.load());
2274 return result;
2275 } else if (action == "abort") {
2276 CoinsViewScanReserver reserver;
2277 if (reserver.reserve()) {
2278 // reserve was possible which means no scan was running
2279 return false;
2280 }
2281 // set the abort flag
2282 g_should_abort_scan = true;
2283 return true;
2284 } else if (action == "start") {
2285 CoinsViewScanReserver reserver;
2286 if (!reserver.reserve()) {
2287 throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
2288 }
2289
2290 if (request.params.size() < 2) {
2291 throw JSONRPCError(RPC_MISC_ERROR, "scanobjects argument is required for the start action");
2292 }
2293
2294 std::set<CScript> needles;
2295 std::map<CScript, std::string> descriptors;
2296 CAmount total_in = 0;
2297
2298 // loop through the scan objects
2299 for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
2300 FlatSigningProvider provider;
2301 auto scripts = EvalDescriptorStringOrObject(scanobject, provider);
2302 for (CScript& script : scripts) {
2303 std::string inferred = InferDescriptor(script, provider)->ToString();
2304 needles.emplace(script);
2305 descriptors.emplace(std::move(script), std::move(inferred));
2306 }
2307 }
2308
2309 // Scan the unspent transaction output set for inputs
2310 UniValue unspents(UniValue::VARR);
2311 std::vector<CTxOut> input_txos;
2312 std::map<COutPoint, Coin> coins;
2313 g_should_abort_scan = false;
2314 int64_t count = 0;
2315 std::unique_ptr<CCoinsViewCursor> pcursor;
2316 const CBlockIndex* tip;
2317 NodeContext& node = EnsureAnyNodeContext(request.context);
2318 {
2320 LOCK(cs_main);
2321 Chainstate& active_chainstate = chainman.ActiveChainstate();
2322 active_chainstate.ForceFlushStateToDisk();
2323 pcursor = CHECK_NONFATAL(active_chainstate.CoinsDB().Cursor());
2324 tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
2325 }
2326 bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins, node.rpc_interruption_point);
2327 result.pushKV("success", res);
2328 result.pushKV("txouts", count);
2329 result.pushKV("height", tip->nHeight);
2330 result.pushKV("bestblock", tip->GetBlockHash().GetHex());
2331
2332 for (const auto& it : coins) {
2333 const COutPoint& outpoint = it.first;
2334 const Coin& coin = it.second;
2335 const CTxOut& txo = coin.out;
2336 const CBlockIndex& coinb_block{*CHECK_NONFATAL(tip->GetAncestor(coin.nHeight))};
2337 input_txos.push_back(txo);
2338 total_in += txo.nValue;
2339
2340 UniValue unspent(UniValue::VOBJ);
2341 unspent.pushKV("txid", outpoint.hash.GetHex());
2342 unspent.pushKV("vout", outpoint.n);
2343 unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
2344 unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
2345 unspent.pushKV("amount", ValueFromAmount(txo.nValue));
2346 unspent.pushKV("coinbase", coin.IsCoinBase());
2347 unspent.pushKV("height", coin.nHeight);
2348 unspent.pushKV("blockhash", coinb_block.GetBlockHash().GetHex());
2349 unspent.pushKV("confirmations", tip->nHeight - coin.nHeight + 1);
2350
2351 unspents.push_back(std::move(unspent));
2352 }
2353 result.pushKV("unspents", std::move(unspents));
2354 result.pushKV("total_amount", ValueFromAmount(total_in));
2355 } else {
2356 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid action '%s'", action));
2357 }
2358 return result;
2359},
2360 };
2361}
2362
2364static std::atomic<int> g_scanfilter_progress;
2365static std::atomic<int> g_scanfilter_progress_height;
2366static std::atomic<bool> g_scanfilter_in_progress;
2367static std::atomic<bool> g_scanfilter_should_abort_scan;
2369{
2370private:
2371 bool m_could_reserve{false};
2372public:
2373 explicit BlockFiltersScanReserver() = default;
2374
2375 bool reserve() {
2377 if (g_scanfilter_in_progress.exchange(true)) {
2378 return false;
2379 }
2380 m_could_reserve = true;
2381 return true;
2382 }
2383
2385 if (m_could_reserve) {
2387 }
2388 }
2389};
2390
2391static bool CheckBlockFilterMatches(BlockManager& blockman, const CBlockIndex& blockindex, const GCSFilter::ElementSet& needles)
2392{
2393 const CBlock block{GetBlockChecked(blockman, blockindex)};
2394 const CBlockUndo block_undo{GetUndoChecked(blockman, blockindex)};
2395
2396 // Check if any of the outputs match the scriptPubKey
2397 for (const auto& tx : block.vtx) {
2398 if (std::any_of(tx->vout.cbegin(), tx->vout.cend(), [&](const auto& txout) {
2399 return needles.count(std::vector<unsigned char>(txout.scriptPubKey.begin(), txout.scriptPubKey.end())) != 0;
2400 })) {
2401 return true;
2402 }
2403 }
2404 // Check if any of the inputs match the scriptPubKey
2405 for (const auto& txundo : block_undo.vtxundo) {
2406 if (std::any_of(txundo.vprevout.cbegin(), txundo.vprevout.cend(), [&](const auto& coin) {
2407 return needles.count(std::vector<unsigned char>(coin.out.scriptPubKey.begin(), coin.out.scriptPubKey.end())) != 0;
2408 })) {
2409 return true;
2410 }
2411 }
2412
2413 return false;
2414}
2415
2417{
2418 return RPCHelpMan{"scanblocks",
2419 "\nReturn relevant blockhashes for given descriptors (requires blockfilterindex).\n"
2420 "This call may take several minutes. Make sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
2421 {
2424 RPCArg{"start_height", RPCArg::Type::NUM, RPCArg::Default{0}, "Height to start to scan from"},
2425 RPCArg{"stop_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"chain tip"}, "Height to stop to scan"},
2426 RPCArg{"filtertype", RPCArg::Type::STR, RPCArg::Default{BlockFilterTypeName(BlockFilterType::BASIC)}, "The type name of the filter"},
2428 {
2429 {"filter_false_positives", RPCArg::Type::BOOL, RPCArg::Default{false}, "Filter false positives (slower and may fail on pruned nodes). Otherwise they may occur at a rate of 1/M"},
2430 },
2432 },
2433 {
2435 RPCResult{"When action=='start'; only returns after scan completes", RPCResult::Type::OBJ, "", "", {
2436 {RPCResult::Type::NUM, "from_height", "The height we started the scan from"},
2437 {RPCResult::Type::NUM, "to_height", "The height we ended the scan at"},
2438 {RPCResult::Type::ARR, "relevant_blocks", "Blocks that may have matched a scanobject.", {
2439 {RPCResult::Type::STR_HEX, "blockhash", "A relevant blockhash"},
2440 }},
2441 {RPCResult::Type::BOOL, "completed", "true if the scan process was not aborted"}
2442 }},
2443 RPCResult{"when action=='status' and a scan is currently in progress", RPCResult::Type::OBJ, "", "", {
2444 {RPCResult::Type::NUM, "progress", "Approximate percent complete"},
2445 {RPCResult::Type::NUM, "current_height", "Height of the block currently being scanned"},
2446 },
2447 },
2449 },
2451 HelpExampleCli("scanblocks", "start '[\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"]' 300000") +
2452 HelpExampleCli("scanblocks", "start '[\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"]' 100 150 basic") +
2453 HelpExampleCli("scanblocks", "status") +
2454 HelpExampleRpc("scanblocks", "\"start\", [\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"], 300000") +
2455 HelpExampleRpc("scanblocks", "\"start\", [\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"], 100, 150, \"basic\"") +
2456 HelpExampleRpc("scanblocks", "\"status\"")
2457 },
2458 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2459{
2461 if (request.params[0].get_str() == "status") {
2462 BlockFiltersScanReserver reserver;
2463 if (reserver.reserve()) {
2464 // no scan in progress
2465 return NullUniValue;
2466 }
2467 ret.pushKV("progress", g_scanfilter_progress.load());
2468 ret.pushKV("current_height", g_scanfilter_progress_height.load());
2469 return ret;
2470 } else if (request.params[0].get_str() == "abort") {
2471 BlockFiltersScanReserver reserver;
2472 if (reserver.reserve()) {
2473 // reserve was possible which means no scan was running
2474 return false;
2475 }
2476 // set the abort flag
2478 return true;
2479 } else if (request.params[0].get_str() == "start") {
2480 BlockFiltersScanReserver reserver;
2481 if (!reserver.reserve()) {
2482 throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
2483 }
2484 const std::string filtertype_name{request.params[4].isNull() ? "basic" : request.params[4].get_str()};
2485
2486 BlockFilterType filtertype;
2487 if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2488 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown filtertype");
2489 }
2490
2491 UniValue options{request.params[5].isNull() ? UniValue::VOBJ : request.params[5]};
2492 bool filter_false_positives{options.exists("filter_false_positives") ? options["filter_false_positives"].get_bool() : false};
2493
2494 BlockFilterIndex* index = GetBlockFilterIndex(filtertype);
2495 if (!index) {
2496 throw JSONRPCError(RPC_MISC_ERROR, "Index is not enabled for filtertype " + filtertype_name);
2497 }
2498
2499 NodeContext& node = EnsureAnyNodeContext(request.context);
2501
2502 // set the start-height
2503 const CBlockIndex* start_index = nullptr;
2504 const CBlockIndex* stop_block = nullptr;
2505 {
2506 LOCK(cs_main);
2507 CChain& active_chain = chainman.ActiveChain();
2508 start_index = active_chain.Genesis();
2509 stop_block = active_chain.Tip(); // If no stop block is provided, stop at the chain tip.
2510 if (!request.params[2].isNull()) {
2511 start_index = active_chain[request.params[2].getInt<int>()];
2512 if (!start_index) {
2513 throw JSONRPCError(RPC_MISC_ERROR, "Invalid start_height");
2514 }
2515 }
2516 if (!request.params[3].isNull()) {
2517 stop_block = active_chain[request.params[3].getInt<int>()];
2518 if (!stop_block || stop_block->nHeight < start_index->nHeight) {
2519 throw JSONRPCError(RPC_MISC_ERROR, "Invalid stop_height");
2520 }
2521 }
2522 }
2523 CHECK_NONFATAL(start_index);
2524 CHECK_NONFATAL(stop_block);
2525
2526 // loop through the scan objects, add scripts to the needle_set
2527 GCSFilter::ElementSet needle_set;
2528 for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
2529 FlatSigningProvider provider;
2530 std::vector<CScript> scripts = EvalDescriptorStringOrObject(scanobject, provider);
2531 for (const CScript& script : scripts) {
2532 needle_set.emplace(script.begin(), script.end());
2533 }
2534 }
2535 UniValue blocks(UniValue::VARR);
2536 const int amount_per_chunk = 10000;
2537 std::vector<BlockFilter> filters;
2538 int start_block_height = start_index->nHeight; // for progress reporting
2539 const int total_blocks_to_process = stop_block->nHeight - start_block_height;
2540
2543 g_scanfilter_progress_height = start_block_height;
2544 bool completed = true;
2545
2546 const CBlockIndex* end_range = nullptr;
2547 do {
2548 node.rpc_interruption_point(); // allow a clean shutdown
2550 completed = false;
2551 break;
2552 }
2553
2554 // split the lookup range in chunks if we are deeper than 'amount_per_chunk' blocks from the stopping block
2555 int start_block = !end_range ? start_index->nHeight : start_index->nHeight + 1; // to not include the previous round 'end_range' block
2556 end_range = (start_block + amount_per_chunk < stop_block->nHeight) ?
2557 WITH_LOCK(::cs_main, return chainman.ActiveChain()[start_block + amount_per_chunk]) :
2558 stop_block;
2559
2560 if (index->LookupFilterRange(start_block, end_range, filters)) {
2561 for (const BlockFilter& filter : filters) {
2562 // compare the elements-set with each filter
2563 if (filter.GetFilter().MatchAny(needle_set)) {
2564 if (filter_false_positives) {
2565 // Double check the filter matches by scanning the block
2566 const CBlockIndex& blockindex = *CHECK_NONFATAL(WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(filter.GetBlockHash())));
2567
2568 if (!CheckBlockFilterMatches(chainman.m_blockman, blockindex, needle_set)) {
2569 continue;
2570 }
2571 }
2572
2573 blocks.push_back(filter.GetBlockHash().GetHex());
2574 }
2575 }
2576 }
2577 start_index = end_range;
2578
2579 // update progress
2580 int blocks_processed = end_range->nHeight - start_block_height;
2581 if (total_blocks_to_process > 0) { // avoid division by zero
2582 g_scanfilter_progress = (int)(100.0 / total_blocks_to_process * blocks_processed);
2583 } else {
2585 }
2587
2588 // Finish if we reached the stop block
2589 } while (start_index != stop_block);
2590
2591 ret.pushKV("from_height", start_block_height);
2592 ret.pushKV("to_height", start_index->nHeight); // start_index is always the last scanned block here
2593 ret.pushKV("relevant_blocks", std::move(blocks));
2594 ret.pushKV("completed", completed);
2595 }
2596 else {
2597 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid action '%s'", request.params[0].get_str()));
2598 }
2599 return ret;
2600},
2601 };
2602}
2603
2605{
2606 return RPCHelpMan{"getdescriptoractivity",
2607 "\nGet spend and receive activity associated with a set of descriptors for a set of blocks. "
2608 "This command pairs well with the `relevant_blocks` output of `scanblocks()`.\n"
2609 "This call may take several minutes. If you encounter timeouts, try specifying no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
2610 {
2611 RPCArg{"blockhashes", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "The list of blockhashes to examine for activity. Order doesn't matter. Must be along main chain or an error is thrown.\n", {
2612 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A valid blockhash"},
2613 }},
2615 {"include_mempool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to include unconfirmed activity"},
2616 },
2617 RPCResult{
2618 RPCResult::Type::OBJ, "", "", {
2619 {RPCResult::Type::ARR, "activity", "events", {
2620 {RPCResult::Type::OBJ, "", "", {
2621 {RPCResult::Type::STR, "type", "always 'spend'"},
2622 {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the spent output"},
2623 {RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "The blockhash this spend appears in (omitted if unconfirmed)"},
2624 {RPCResult::Type::NUM, "height", /*optional=*/true, "Height of the spend (omitted if unconfirmed)"},
2625 {RPCResult::Type::STR_HEX, "spend_txid", "The txid of the spending transaction"},
2626 {RPCResult::Type::NUM, "spend_vout", "The vout of the spend"},
2627 {RPCResult::Type::STR_HEX, "prevout_txid", "The txid of the prevout"},
2628 {RPCResult::Type::NUM, "prevout_vout", "The vout of the prevout"},
2629 {RPCResult::Type::OBJ, "prevout_spk", "", ScriptPubKeyDoc()},
2630 }},
2631 {RPCResult::Type::OBJ, "", "", {
2632 {RPCResult::Type::STR, "type", "always 'receive'"},
2633 {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the new output"},
2634 {RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "The block that this receive is in (omitted if unconfirmed)"},
2635 {RPCResult::Type::NUM, "height", /*optional=*/true, "The height of the receive (omitted if unconfirmed)"},
2636 {RPCResult::Type::STR_HEX, "txid", "The txid of the receiving transaction"},
2637 {RPCResult::Type::NUM, "vout", "The vout of the receiving output"},
2638 {RPCResult::Type::OBJ, "output_spk", "", ScriptPubKeyDoc()},
2639 }},
2640 // TODO is the skip_type_check avoidable with a heterogeneous ARR?
2641 }, /*skip_type_check=*/true},
2642 },
2643 },
2645 HelpExampleCli("getdescriptoractivity", "'[\"000000000000000000001347062c12fded7c528943c8ce133987e2e2f5a840ee\"]' '[\"addr(bc1qzl6nsgqzu89a66l50cvwapnkw5shh23zarqkw9)\"]'")
2646 },
2647 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2648{
2650 UniValue activity(UniValue::VARR);
2651 NodeContext& node = EnsureAnyNodeContext(request.context);
2653
2654 struct CompareByHeightAscending {
2655 bool operator()(const CBlockIndex* a, const CBlockIndex* b) const {
2656 return a->nHeight < b->nHeight;
2657 }
2658 };
2659
2660 std::set<const CBlockIndex*, CompareByHeightAscending> blockindexes_sorted;
2661
2662 {
2663 // Validate all given blockhashes, and ensure blocks are along a single chain.
2664 LOCK(::cs_main);
2665 for (const UniValue& blockhash : request.params[0].get_array().getValues()) {
2666 uint256 bhash = ParseHashV(blockhash, "blockhash");
2667 CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(bhash);
2668 if (!pindex) {
2669 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
2670 }
2671 if (!chainman.ActiveChain().Contains(pindex)) {
2672 throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain");
2673 }
2674 blockindexes_sorted.insert(pindex);
2675 }
2676 }
2677
2678 std::set<CScript> scripts_to_watch;
2679
2680 // Determine scripts to watch.
2681 for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
2682 FlatSigningProvider provider;
2683 std::vector<CScript> scripts = EvalDescriptorStringOrObject(scanobject, provider);
2684
2685 for (const CScript& script : scripts) {
2686 scripts_to_watch.insert(script);
2687 }
2688 }
2689
2690 const auto AddSpend = [&](
2691 const CScript& spk,
2692 const CAmount val,
2693 const CTransactionRef& tx,
2694 int vin,
2695 const CTxIn& txin,
2696 const CBlockIndex* index
2697 ) {
2698 UniValue event(UniValue::VOBJ);
2699 UniValue spkUv(UniValue::VOBJ);
2700 ScriptToUniv(spk, /*out=*/spkUv, /*include_hex=*/true, /*include_address=*/true);
2701
2702 event.pushKV("type", "spend");
2703 event.pushKV("amount", ValueFromAmount(val));
2704 if (index) {
2705 event.pushKV("blockhash", index->GetBlockHash().ToString());
2706 event.pushKV("height", index->nHeight);
2707 }
2708 event.pushKV("spend_txid", tx->GetHash().ToString());
2709 event.pushKV("spend_vin", vin);
2710 event.pushKV("prevout_txid", txin.prevout.hash.ToString());
2711 event.pushKV("prevout_vout", txin.prevout.n);
2712 event.pushKV("prevout_spk", spkUv);
2713
2714 return event;
2715 };
2716
2717 const auto AddReceive = [&](const CTxOut& txout, const CBlockIndex* index, int vout, const CTransactionRef& tx) {
2718 UniValue event(UniValue::VOBJ);
2719 UniValue spkUv(UniValue::VOBJ);
2720 ScriptToUniv(txout.scriptPubKey, /*out=*/spkUv, /*include_hex=*/true, /*include_address=*/true);
2721
2722 event.pushKV("type", "receive");
2723 event.pushKV("amount", ValueFromAmount(txout.nValue));
2724 if (index) {
2725 event.pushKV("blockhash", index->GetBlockHash().ToString());
2726 event.pushKV("height", index->nHeight);
2727 }
2728 event.pushKV("txid", tx->GetHash().ToString());
2729 event.pushKV("vout", vout);
2730 event.pushKV("output_spk", spkUv);
2731
2732 return event;
2733 };
2734
2735 BlockManager* blockman;
2736 Chainstate& active_chainstate = chainman.ActiveChainstate();
2737 {
2738 LOCK(::cs_main);
2739 blockman = CHECK_NONFATAL(&active_chainstate.m_blockman);
2740 }
2741
2742 for (const CBlockIndex* blockindex : blockindexes_sorted) {
2743 const CBlock block{GetBlockChecked(chainman.m_blockman, *blockindex)};
2744 const CBlockUndo block_undo{GetUndoChecked(*blockman, *blockindex)};
2745
2746 for (size_t i = 0; i < block.vtx.size(); ++i) {
2747 const auto& tx = block.vtx.at(i);
2748
2749 if (!tx->IsCoinBase()) {
2750 // skip coinbase; spends can't happen there.
2751 const auto& txundo = block_undo.vtxundo.at(i - 1);
2752
2753 for (size_t vin_idx = 0; vin_idx < tx->vin.size(); ++vin_idx) {
2754 const auto& coin = txundo.vprevout.at(vin_idx);
2755 const auto& txin = tx->vin.at(vin_idx);
2756 if (scripts_to_watch.contains(coin.out.scriptPubKey)) {
2757 activity.push_back(AddSpend(
2758 coin.out.scriptPubKey, coin.out.nValue, tx, vin_idx, txin, blockindex));
2759 }
2760 }
2761 }
2762
2763 for (size_t vout_idx = 0; vout_idx < tx->vout.size(); ++vout_idx) {
2764 const auto& vout = tx->vout.at(vout_idx);
2765 if (scripts_to_watch.contains(vout.scriptPubKey)) {
2766 activity.push_back(AddReceive(vout, blockindex, vout_idx, tx));
2767 }
2768 }
2769 }
2770 }
2771
2772 bool search_mempool = true;
2773 if (!request.params[2].isNull()) {
2774 search_mempool = request.params[2].get_bool();
2775 }
2776
2777 if (search_mempool) {
2778 const CTxMemPool& mempool = EnsureMemPool(node);
2779 LOCK(::cs_main);
2780 LOCK(mempool.cs);
2781 const CCoinsViewCache& coins_view = &active_chainstate.CoinsTip();
2782
2783 for (const CTxMemPoolEntry& e : mempool.entryAll()) {
2784 const auto& tx = e.GetSharedTx();
2785
2786 for (size_t vin_idx = 0; vin_idx < tx->vin.size(); ++vin_idx) {
2787 CScript scriptPubKey;
2788 CAmount value;
2789 const auto& txin = tx->vin.at(vin_idx);
2790 std::optional<Coin> coin = coins_view.GetCoin(txin.prevout);
2791
2792 // Check if the previous output is in the chain
2793 if (!coin) {
2794 // If not found in the chain, check the mempool. Likely, this is a
2795 // child transaction of another transaction in the mempool.
2796 CTransactionRef prev_tx = CHECK_NONFATAL(mempool.get(txin.prevout.hash));
2797
2798 if (txin.prevout.n >= prev_tx->vout.size()) {
2799 throw std::runtime_error("Invalid output index");
2800 }
2801 const CTxOut& out = prev_tx->vout[txin.prevout.n];
2802 scriptPubKey = out.scriptPubKey;
2803 value = out.nValue;
2804 } else {
2805 // Coin found in the chain
2806 const CTxOut& out = coin->out;
2807 scriptPubKey = out.scriptPubKey;
2808 value = out.nValue;
2809 }
2810
2811 if (scripts_to_watch.contains(scriptPubKey)) {
2812 UniValue event(UniValue::VOBJ);
2813 activity.push_back(AddSpend(
2814 scriptPubKey, value, tx, vin_idx, txin, nullptr));
2815 }
2816 }
2817
2818 for (size_t vout_idx = 0; vout_idx < tx->vout.size(); ++vout_idx) {
2819 const auto& vout = tx->vout.at(vout_idx);
2820 if (scripts_to_watch.contains(vout.scriptPubKey)) {
2821 activity.push_back(AddReceive(vout, nullptr, vout_idx, tx));
2822 }
2823 }
2824 }
2825 }
2826
2827 ret.pushKV("activity", activity);
2828 return ret;
2829},
2830 };
2831}
2832
2834{
2835 return RPCHelpMan{"getblockfilter",
2836 "\nRetrieve a BIP 157 content filter for a particular block.\n",
2837 {
2838 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hash of the block"},
2839 {"filtertype", RPCArg::Type::STR, RPCArg::Default{BlockFilterTypeName(BlockFilterType::BASIC)}, "The type name of the filter"},
2840 },
2841 RPCResult{
2842 RPCResult::Type::OBJ, "", "",
2843 {
2844 {RPCResult::Type::STR_HEX, "filter", "the hex-encoded filter data"},
2845 {RPCResult::Type::STR_HEX, "header", "the hex-encoded filter header"},
2846 }},
2848 HelpExampleCli("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" \"basic\"") +
2849 HelpExampleRpc("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\", \"basic\"")
2850 },
2851 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2852{
2853 uint256 block_hash = ParseHashV(request.params[0], "blockhash");
2854 std::string filtertype_name = BlockFilterTypeName(BlockFilterType::BASIC);
2855 if (!request.params[1].isNull()) {
2856 filtertype_name = request.params[1].get_str();
2857 }
2858
2859 BlockFilterType filtertype;
2860 if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2861 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown filtertype");
2862 }
2863
2864 BlockFilterIndex* index = GetBlockFilterIndex(filtertype);
2865 if (!index) {
2866 throw JSONRPCError(RPC_MISC_ERROR, "Index is not enabled for filtertype " + filtertype_name);
2867 }
2868
2869 const CBlockIndex* block_index;
2870 bool block_was_connected;
2871 {
2872 ChainstateManager& chainman = EnsureAnyChainman(request.context);
2873 LOCK(cs_main);
2874 block_index = chainman.m_blockman.LookupBlockIndex(block_hash);
2875 if (!block_index) {
2876 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
2877 }
2878 block_was_connected = block_index->IsValid(BLOCK_VALID_SCRIPTS);
2879 }
2880
2881 bool index_ready = index->BlockUntilSyncedToCurrentChain();
2882
2883 BlockFilter filter;
2884 uint256 filter_header;
2885 if (!index->LookupFilter(block_index, filter) ||
2886 !index->LookupFilterHeader(block_index, filter_header)) {
2887 int err_code;
2888 std::string errmsg = "Filter not found.";
2889
2890 if (!block_was_connected) {
2891 err_code = RPC_INVALID_ADDRESS_OR_KEY;
2892 errmsg += " Block was not connected to active chain.";
2893 } else if (!index_ready) {
2894 err_code = RPC_MISC_ERROR;
2895 errmsg += " Block filters are still in the process of being indexed.";
2896 } else {
2897 err_code = RPC_INTERNAL_ERROR;
2898 errmsg += " This error is unexpected and indicates index corruption.";
2899 }
2900
2901 throw JSONRPCError(err_code, errmsg);
2902 }
2903
2905 ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
2906 ret.pushKV("header", filter_header.GetHex());
2907 return ret;
2908},
2909 };
2910}
2911
2917{
2919public:
2920 NetworkDisable(CConnman& connman) : m_connman(connman) {
2923 throw JSONRPCError(RPC_MISC_ERROR, "Network activity could not be suspended.");
2924 }
2925 };
2928 };
2929};
2930
2936{
2939public:
2940 TemporaryRollback(ChainstateManager& chainman, const CBlockIndex& index) : m_chainman(chainman), m_invalidate_index(index) {
2942 };
2945 };
2946};
2947
2954{
2955 return RPCHelpMan{
2956 "dumptxoutset",
2957 "Write the serialized UTXO set to a file. This can be used in loadtxoutset afterwards if this snapshot height is supported in the chainparams as well.\n\n"
2958 "Unless the \"latest\" type is requested, the node will roll back to the requested height and network activity will be suspended during this process. "
2959 "Because of this it is discouraged to interact with the node in any other way during the execution of this call to avoid inconsistent results and race conditions, particularly RPCs that interact with blockstorage.\n\n"
2960 "This call may take several minutes. Make sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
2961 {
2962 {"path", RPCArg::Type::STR, RPCArg::Optional::NO, "Path to the output file. If relative, will be prefixed by datadir."},
2963 {"type", RPCArg::Type::STR, RPCArg::Default(""), "The type of snapshot to create. Can be \"latest\" to create a snapshot of the current UTXO set or \"rollback\" to temporarily roll back the state of the node to a historical block before creating the snapshot of a historical UTXO set. This parameter can be omitted if a separate \"rollback\" named parameter is specified indicating the height or hash of a specific historical block. If \"rollback\" is specified and separate \"rollback\" named parameter is not specified, this will roll back to the latest valid snapshot block that can currently be loaded with loadtxoutset."},
2965 {
2967 "Height or hash of the block to roll back to before creating the snapshot. Note: The further this number is from the tip, the longer this process will take. Consider setting a higher -rpcclienttimeout value in this case.",
2968 RPCArgOptions{.skip_type_check = true, .type_str = {"", "string or numeric"}}},
2969 },
2970 },
2971 },
2972 RPCResult{
2973 RPCResult::Type::OBJ, "", "",
2974 {
2975 {RPCResult::Type::NUM, "coins_written", "the number of coins written in the snapshot"},
2976 {RPCResult::Type::STR_HEX, "base_hash", "the hash of the base of the snapshot"},
2977 {RPCResult::Type::NUM, "base_height", "the height of the base of the snapshot"},
2978 {RPCResult::Type::STR, "path", "the absolute path that the snapshot was written to"},
2979 {RPCResult::Type::STR_HEX, "txoutset_hash", "the hash of the UTXO set contents"},
2980 {RPCResult::Type::NUM, "nchaintx", "the number of transactions in the chain up to and including the base block"},
2981 }
2982 },
2984 HelpExampleCli("-rpcclienttimeout=0 dumptxoutset", "utxo.dat latest") +
2985 HelpExampleCli("-rpcclienttimeout=0 dumptxoutset", "utxo.dat rollback") +
2986 HelpExampleCli("-rpcclienttimeout=0 -named dumptxoutset", R"(utxo.dat rollback=853456)")
2987 },
2988 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2989{
2990 NodeContext& node = EnsureAnyNodeContext(request.context);
2991 const CBlockIndex* tip{WITH_LOCK(::cs_main, return node.chainman->ActiveChain().Tip())};
2992 const CBlockIndex* target_index{nullptr};
2993 const std::string snapshot_type{self.Arg<std::string>("type")};
2994 const UniValue options{request.params[2].isNull() ? UniValue::VOBJ : request.params[2]};
2995 if (options.exists("rollback")) {
2996 if (!snapshot_type.empty() && snapshot_type != "rollback") {
2997 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid snapshot type \"%s\" specified with rollback option", snapshot_type));
2998 }
2999 target_index = ParseHashOrHeight(options["rollback"], *node.chainman);
3000 } else if (snapshot_type == "rollback") {
3001 auto snapshot_heights = node.chainman->GetParams().GetAvailableSnapshotHeights();
3002 CHECK_NONFATAL(snapshot_heights.size() > 0);
3003 auto max_height = std::max_element(snapshot_heights.begin(), snapshot_heights.end());
3004 target_index = ParseHashOrHeight(*max_height, *node.chainman);
3005 } else if (snapshot_type == "latest") {
3006 target_index = tip;
3007 } else {
3008 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid snapshot type \"%s\" specified. Please specify \"rollback\" or \"latest\"", snapshot_type));
3009 }
3010
3011 const ArgsManager& args{EnsureAnyArgsman(request.context)};
3012 const fs::path path = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(request.params[0].get_str()));
3013 // Write to a temporary path and then move into `path` on completion
3014 // to avoid confusion due to an interruption.
3015 const fs::path temppath = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(request.params[0].get_str() + ".incomplete"));
3016
3017 if (fs::exists(path)) {
3018 throw JSONRPCError(
3020 path.utf8string() + " already exists. If you are sure this is what you want, "
3021 "move it out of the way first");
3022 }
3023
3024 FILE* file{fsbridge::fopen(temppath, "wb")};
3025 AutoFile afile{file};
3026 if (afile.IsNull()) {
3027 throw JSONRPCError(
3029 "Couldn't open file " + temppath.utf8string() + " for writing.");
3030 }
3031
3032 CConnman& connman = EnsureConnman(node);
3033 const CBlockIndex* invalidate_index{nullptr};
3034 std::optional<NetworkDisable> disable_network;
3035 std::optional<TemporaryRollback> temporary_rollback;
3036
3037 // If the user wants to dump the txoutset of the current tip, we don't have
3038 // to roll back at all
3039 if (target_index != tip) {
3040 // If the node is running in pruned mode we ensure all necessary block
3041 // data is available before starting to roll back.
3042 if (node.chainman->m_blockman.IsPruneMode()) {
3043 LOCK(node.chainman->GetMutex());
3044 const CBlockIndex* current_tip{node.chainman->ActiveChain().Tip()};
3045 const CBlockIndex* first_block{node.chainman->m_blockman.GetFirstBlock(*current_tip, /*status_mask=*/BLOCK_HAVE_MASK)};
3046 if (first_block->nHeight > target_index->nHeight) {
3047 throw JSONRPCError(RPC_MISC_ERROR, "Could not roll back to requested height since necessary block data is already pruned.");
3048 }
3049 }
3050
3051 // Suspend network activity for the duration of the process when we are
3052 // rolling back the chain to get a utxo set from a past height. We do
3053 // this so we don't punish peers that send us that send us data that
3054 // seems wrong in this temporary state. For example a normal new block
3055 // would be classified as a block connecting an invalid block.
3056 // Skip if the network is already disabled because this
3057 // automatically re-enables the network activity at the end of the
3058 // process which may not be what the user wants.
3059 if (connman.GetNetworkActive()) {
3060 disable_network.emplace(connman);
3061 }
3062
3063 invalidate_index = WITH_LOCK(::cs_main, return node.chainman->ActiveChain().Next(target_index));
3064 temporary_rollback.emplace(*node.chainman, *invalidate_index);
3065 }
3066
3067 Chainstate* chainstate;
3068 std::unique_ptr<CCoinsViewCursor> cursor;
3069 CCoinsStats stats;
3070 {
3071 // Lock the chainstate before calling PrepareUtxoSnapshot, to be able
3072 // to get a UTXO database cursor while the chain is pointing at the
3073 // target block. After that, release the lock while calling
3074 // WriteUTXOSnapshot. The cursor will remain valid and be used by
3075 // WriteUTXOSnapshot to write a consistent snapshot even if the
3076 // chainstate changes.
3077 LOCK(node.chainman->GetMutex());
3078 chainstate = &node.chainman->ActiveChainstate();
3079 // In case there is any issue with a block being read from disk we need
3080 // to stop here, otherwise the dump could still be created for the wrong
3081 // height.
3082 // The new tip could also not be the target block if we have a stale
3083 // sister block of invalidate_index. This block (or a descendant) would
3084 // be activated as the new tip and we would not get to new_tip_index.
3085 if (target_index != chainstate->m_chain.Tip()) {
3086 LogWarning("dumptxoutset failed to roll back to requested height, reverting to tip.\n");
3087 throw JSONRPCError(RPC_MISC_ERROR, "Could not roll back to requested height.");
3088 } else {
3089 std::tie(cursor, stats, tip) = PrepareUTXOSnapshot(*chainstate, node.rpc_interruption_point);
3090 }
3091 }
3092
3093 UniValue result = WriteUTXOSnapshot(*chainstate, cursor.get(), &stats, tip, afile, path, temppath, node.rpc_interruption_point);
3094 fs::rename(temppath, path);
3095
3096 result.pushKV("path", path.utf8string());
3097 return result;
3098},
3099 };
3100}
3101
3102std::tuple<std::unique_ptr<CCoinsViewCursor>, CCoinsStats, const CBlockIndex*>
3104 Chainstate& chainstate,
3105 const std::function<void()>& interruption_point)
3106{
3107 std::unique_ptr<CCoinsViewCursor> pcursor;
3108 std::optional<CCoinsStats> maybe_stats;
3109 const CBlockIndex* tip;
3110
3111 {
3112 // We need to lock cs_main to ensure that the coinsdb isn't written to
3113 // between (i) flushing coins cache to disk (coinsdb), (ii) getting stats
3114 // based upon the coinsdb, and (iii) constructing a cursor to the
3115 // coinsdb for use in WriteUTXOSnapshot.
3116 //
3117 // Cursors returned by leveldb iterate over snapshots, so the contents
3118 // of the pcursor will not be affected by simultaneous writes during
3119 // use below this block.
3120 //
3121 // See discussion here:
3122 // https://github.com/bitcoin/bitcoin/pull/15606#discussion_r274479369
3123 //
3125
3126 chainstate.ForceFlushStateToDisk();
3127
3128 maybe_stats = GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman, CoinStatsHashType::HASH_SERIALIZED, interruption_point);
3129 if (!maybe_stats) {
3130 throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
3131 }
3132
3133 pcursor = chainstate.CoinsDB().Cursor();
3134 tip = CHECK_NONFATAL(chainstate.m_blockman.LookupBlockIndex(maybe_stats->hashBlock));
3135 }
3136
3137 return {std::move(pcursor), *CHECK_NONFATAL(maybe_stats), tip};
3138}
3139
3141 Chainstate& chainstate,
3142 CCoinsViewCursor* pcursor,
3143 CCoinsStats* maybe_stats,
3144 const CBlockIndex* tip,
3145 AutoFile& afile,
3146 const fs::path& path,
3147 const fs::path& temppath,
3148 const std::function<void()>& interruption_point)
3149{
3150 LOG_TIME_SECONDS(strprintf("writing UTXO snapshot at height %s (%s) to file %s (via %s)",
3151 tip->nHeight, tip->GetBlockHash().ToString(),
3152 fs::PathToString(path), fs::PathToString(temppath)));
3153
3154 SnapshotMetadata metadata{chainstate.m_chainman.GetParams().MessageStart(), tip->GetBlockHash(), maybe_stats->coins_count};
3155
3156 afile << metadata;
3157
3158 COutPoint key;
3159 Txid last_hash;
3160 Coin coin;
3161 unsigned int iter{0};
3162 size_t written_coins_count{0};
3163 std::vector<std::pair<uint32_t, Coin>> coins;
3164
3165 // To reduce space the serialization format of the snapshot avoids
3166 // duplication of tx hashes. The code takes advantage of the guarantee by
3167 // leveldb that keys are lexicographically sorted.
3168 // In the coins vector we collect all coins that belong to a certain tx hash
3169 // (key.hash) and when we have them all (key.hash != last_hash) we write
3170 // them to file using the below lambda function.
3171 // See also https://github.com/bitcoin/bitcoin/issues/25675
3172 auto write_coins_to_file = [&](AutoFile& afile, const Txid& last_hash, const std::vector<std::pair<uint32_t, Coin>>& coins, size_t& written_coins_count) {
3173 afile << last_hash;
3174 WriteCompactSize(afile, coins.size());
3175 for (const auto& [n, coin] : coins) {
3176 WriteCompactSize(afile, n);
3177 afile << coin;
3178 ++written_coins_count;
3179 }
3180 };
3181
3182 pcursor->GetKey(key);
3183 last_hash = key.hash;
3184 while (pcursor->Valid()) {
3185 if (iter % 5000 == 0) interruption_point();
3186 ++iter;
3187 if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
3188 if (key.hash != last_hash) {
3189 write_coins_to_file(afile, last_hash, coins, written_coins_count);
3190 last_hash = key.hash;
3191 coins.clear();
3192 }
3193 coins.emplace_back(key.n, coin);
3194 }
3195 pcursor->Next();
3196 }
3197
3198 if (!coins.empty()) {
3199 write_coins_to_file(afile, last_hash, coins, written_coins_count);
3200 }
3201
3202 CHECK_NONFATAL(written_coins_count == maybe_stats->coins_count);
3203
3204 afile.fclose();
3205
3206 UniValue result(UniValue::VOBJ);
3207 result.pushKV("coins_written", written_coins_count);
3208 result.pushKV("base_hash", tip->GetBlockHash().ToString());
3209 result.pushKV("base_height", tip->nHeight);
3210 result.pushKV("path", path.utf8string());
3211 result.pushKV("txoutset_hash", maybe_stats->hashSerialized.ToString());
3212 result.pushKV("nchaintx", tip->m_chain_tx_count);
3213 return result;
3214}
3215
3218 Chainstate& chainstate,
3219 AutoFile& afile,
3220 const fs::path& path,
3221 const fs::path& tmppath)
3222{
3223 auto [cursor, stats, tip]{WITH_LOCK(::cs_main, return PrepareUTXOSnapshot(chainstate, node.rpc_interruption_point))};
3224 return WriteUTXOSnapshot(chainstate, cursor.get(), &stats, tip, afile, path, tmppath, node.rpc_interruption_point);
3225}
3226
3228{
3229 return RPCHelpMan{
3230 "loadtxoutset",
3231 "Load the serialized UTXO set from a file.\n"
3232 "Once this snapshot is loaded, its contents will be "
3233 "deserialized into a second chainstate data structure, which is then used to sync to "
3234 "the network's tip. "
3235 "Meanwhile, the original chainstate will complete the initial block download process in "
3236 "the background, eventually validating up to the block that the snapshot is based upon.\n\n"
3237
3238 "The result is a usable bitcoind instance that is current with the network tip in a "
3239 "matter of minutes rather than hours. UTXO snapshot are typically obtained from "
3240 "third-party sources (HTTP, torrent, etc.) which is reasonable since their "
3241 "contents are always checked by hash.\n\n"
3242
3243 "You can find more information on this process in the `assumeutxo` design "
3244 "document (<https://github.com/bitcoin/bitcoin/blob/master/doc/design/assumeutxo.md>).",
3245 {
3246 {"path",
3249 "path to the snapshot file. If relative, will be prefixed by datadir."},
3250 },
3251 RPCResult{
3252 RPCResult::Type::OBJ, "", "",
3253 {
3254 {RPCResult::Type::NUM, "coins_loaded", "the number of coins loaded from the snapshot"},
3255 {RPCResult::Type::STR_HEX, "tip_hash", "the hash of the base of the snapshot"},
3256 {RPCResult::Type::NUM, "base_height", "the height of the base of the snapshot"},
3257 {RPCResult::Type::STR, "path", "the absolute path that the snapshot was loaded from"},
3258 }
3259 },
3261 HelpExampleCli("-rpcclienttimeout=0 loadtxoutset", "utxo.dat")
3262 },
3263 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
3264{
3265 NodeContext& node = EnsureAnyNodeContext(request.context);
3267 const fs::path path{AbsPathForConfigVal(EnsureArgsman(node), fs::u8path(self.Arg<std::string>("path")))};
3268
3269 FILE* file{fsbridge::fopen(path, "rb")};
3270 AutoFile afile{file};
3271 if (afile.IsNull()) {
3272 throw JSONRPCError(
3274 "Couldn't open file " + path.utf8string() + " for reading.");
3275 }
3276
3277 SnapshotMetadata metadata{chainman.GetParams().MessageStart()};
3278 try {
3279 afile >> metadata;
3280 } catch (const std::ios_base::failure& e) {
3281 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("Unable to parse metadata: %s", e.what()));
3282 }
3283
3284 auto activation_result{chainman.ActivateSnapshot(afile, metadata, false)};
3285 if (!activation_result) {
3286 throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to load UTXO snapshot: %s. (%s)", util::ErrorString(activation_result).original, path.utf8string()));
3287 }
3288
3289 // Because we can't provide historical blocks during tip or background sync.
3290 // Update local services to reflect we are a limited peer until we are fully sync.
3291 node.connman->RemoveLocalServices(NODE_NETWORK);
3292 // Setting the limited state is usually redundant because the node can always
3293 // provide the last 288 blocks, but it doesn't hurt to set it.
3294 node.connman->AddLocalServices(NODE_NETWORK_LIMITED);
3295
3296 CBlockIndex& snapshot_index{*CHECK_NONFATAL(*activation_result)};
3297
3298 UniValue result(UniValue::VOBJ);
3299 result.pushKV("coins_loaded", metadata.m_coins_count);
3300 result.pushKV("tip_hash", snapshot_index.GetBlockHash().ToString());
3301 result.pushKV("base_height", snapshot_index.nHeight);
3302 result.pushKV("path", fs::PathToString(path));
3303 return result;
3304},
3305 };
3306}
3307
3308const std::vector<RPCResult> RPCHelpForChainstate{
3309 {RPCResult::Type::NUM, "blocks", "number of blocks in this chainstate"},
3310 {RPCResult::Type::STR_HEX, "bestblockhash", "blockhash of the tip"},
3311 {RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},
3312 {RPCResult::Type::STR_HEX, "target", "The difficulty target"},
3313 {RPCResult::Type::NUM, "difficulty", "difficulty of the tip"},
3314 {RPCResult::Type::NUM, "verificationprogress", "progress towards the network tip"},
3315 {RPCResult::Type::STR_HEX, "snapshot_blockhash", /*optional=*/true, "the base block of the snapshot this chainstate is based on, if any"},
3316 {RPCResult::Type::NUM, "coins_db_cache_bytes", "size of the coinsdb cache"},
3317 {RPCResult::Type::NUM, "coins_tip_cache_bytes", "size of the coinstip cache"},
3318 {RPCResult::Type::BOOL, "validated", "whether the chainstate is fully validated. True if all blocks in the chainstate were validated, false if the chain is based on a snapshot and the snapshot has not yet been validated."},
3319};
3320
3322{
3323return RPCHelpMan{
3324 "getchainstates",
3325 "\nReturn information about chainstates.\n",
3326 {},
3327 RPCResult{
3328 RPCResult::Type::OBJ, "", "", {
3329 {RPCResult::Type::NUM, "headers", "the number of headers seen so far"},
3330 {RPCResult::Type::ARR, "chainstates", "list of the chainstates ordered by work, with the most-work (active) chainstate last", {{RPCResult::Type::OBJ, "", "", RPCHelpForChainstate},}},
3331 }
3332 },
3334 HelpExampleCli("getchainstates", "")
3335 + HelpExampleRpc("getchainstates", "")
3336 },
3337 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
3338{
3339 LOCK(cs_main);
3341
3342 ChainstateManager& chainman = EnsureAnyChainman(request.context);
3343
3344 auto make_chain_data = [&](const Chainstate& cs, bool validated) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
3347 if (!cs.m_chain.Tip()) {
3348 return data;
3349 }
3350 const CChain& chain = cs.m_chain;
3351 const CBlockIndex* tip = chain.Tip();
3352
3353 data.pushKV("blocks", (int)chain.Height());
3354 data.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
3355 data.pushKV("bits", strprintf("%08x", tip->nBits));
3356 data.pushKV("target", GetTarget(*tip, chainman.GetConsensus().powLimit).GetHex());
3357 data.pushKV("difficulty", GetDifficulty(*tip));
3358 data.pushKV("verificationprogress", chainman.GuessVerificationProgress(tip));
3359 data.pushKV("coins_db_cache_bytes", cs.m_coinsdb_cache_size_bytes);
3360 data.pushKV("coins_tip_cache_bytes", cs.m_coinstip_cache_size_bytes);
3361 if (cs.m_from_snapshot_blockhash) {
3362 data.pushKV("snapshot_blockhash", cs.m_from_snapshot_blockhash->ToString());
3363 }
3364 data.pushKV("validated", validated);
3365 return data;
3366 };
3367
3368 obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
3369
3370 const auto& chainstates = chainman.GetAll();
3371 UniValue obj_chainstates{UniValue::VARR};
3372 for (Chainstate* cs : chainstates) {
3373 obj_chainstates.push_back(make_chain_data(*cs, !cs->m_from_snapshot_blockhash || chainstates.size() == 1));
3374 }
3375 obj.pushKV("chainstates", std::move(obj_chainstates));
3376 return obj;
3377}
3378 };
3379}
3380
3381
3383{
3384 static const CRPCCommand commands[]{
3385 {"blockchain", &getblockchaininfo},
3386 {"blockchain", &getchaintxstats},
3387 {"blockchain", &getblockstats},
3388 {"blockchain", &getbestblockhash},
3389 {"blockchain", &getblockcount},
3390 {"blockchain", &getblock},
3391 {"blockchain", &getblockfrompeer},
3392 {"blockchain", &getblockhash},
3393 {"blockchain", &getblockheader},
3394 {"blockchain", &getchaintips},
3395 {"blockchain", &getdifficulty},
3396 {"blockchain", &getdeploymentinfo},
3397 {"blockchain", &gettxout},
3398 {"blockchain", &gettxoutsetinfo},
3399 {"blockchain", &pruneblockchain},
3400 {"blockchain", &verifychain},
3401 {"blockchain", &preciousblock},
3402 {"blockchain", &scantxoutset},
3403 {"blockchain", &scanblocks},
3404 {"blockchain", &getdescriptoractivity},
3405 {"blockchain", &getblockfilter},
3406 {"blockchain", &dumptxoutset},
3407 {"blockchain", &loadtxoutset},
3408 {"blockchain", &getchainstates},
3409 {"hidden", &invalidateblock},
3410 {"hidden", &reconsiderblock},
3411 {"hidden", &waitfornewblock},
3412 {"hidden", &waitforblock},
3413 {"hidden", &waitforblockheight},
3415 };
3416 for (const auto& c : commands) {
3417 t.appendCommand(c.name, &c);
3418 }
3419}
static constexpr CAmount MAX_MONEY
No amount larger than this (in satoshi) is valid.
Definition: amount.h:26
bool MoneyRange(const CAmount &nValue)
Definition: amount.h:27
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
fs::path AbsPathForConfigVal(const ArgsManager &args, const fs::path &path, bool net_specific=true)
Most paths passed as configuration arguments are treated as relative to the datadir if they are not a...
Definition: config.cpp:226
int ret
ArgsManager & args
Definition: bitcoind.cpp:277
static RPCHelpMan getblock()
Definition: blockchain.cpp:700
static RPCHelpMan getdifficulty()
Definition: blockchain.cpp:431
static const auto scan_result_abort
static std::atomic< bool > g_scan_in_progress
static bool SetHasKeys(const std::set< T > &set)
static RPCHelpMan reconsiderblock()
static T CalculateTruncatedMedian(std::vector< T > &scores)
static RPCHelpMan invalidateblock()
static int ComputeNextBlockAndDepth(const CBlockIndex &tip, const CBlockIndex &blockindex, const CBlockIndex *&next)
Definition: blockchain.cpp:111
const RPCResult getblock_vin
Definition: blockchain.cpp:676
static RPCHelpMan syncwithvalidationinterfacequeue()
Definition: blockchain.cpp:412
static CBlockUndo GetUndoChecked(BlockManager &blockman, const CBlockIndex &blockindex)
Definition: blockchain.cpp:657
static RPCHelpMan getchaintips()
static RPCHelpMan loadtxoutset()
static RPCHelpMan gettxoutsetinfo()
Definition: blockchain.cpp:939
static RPCHelpMan getchainstates()
std::tuple< std::unique_ptr< CCoinsViewCursor >, CCoinsStats, const CBlockIndex * > PrepareUTXOSnapshot(Chainstate &chainstate, const std::function< void()> &interruption_point)
static std::atomic< int > g_scanfilter_progress_height
static RPCHelpMan getblockstats()
void CheckBlockDataAvailability(BlockManager &blockman, const CBlockIndex &blockindex, bool check_for_undo)
Definition: blockchain.cpp:606
static std::atomic< bool > g_scanfilter_should_abort_scan
static std::atomic< int > g_scanfilter_progress
RAII object to prevent concurrency issue when scanning blockfilters.
static void SoftForkDescPushBack(const CBlockIndex *blockindex, UniValue &softforks, const ChainstateManager &chainman, Consensus::BuriedDeployment dep)
static RPCHelpMan preciousblock()
static constexpr size_t PER_UTXO_OVERHEAD
static RPCHelpMan getdescriptoractivity()
double GetDifficulty(const CBlockIndex &blockindex)
Get the difficulty of the net wrt to the given block index.
Definition: blockchain.cpp:91
static const auto scan_objects_arg_desc
static RPCHelpMan scantxoutset()
CoinStatsHashType ParseHashType(const std::string &hash_type_input)
Definition: blockchain.cpp:896
static bool CheckBlockFilterMatches(BlockManager &blockman, const CBlockIndex &blockindex, const GCSFilter::ElementSet &needles)
void InvalidateBlock(ChainstateManager &chainman, const uint256 block_hash)
static std::atomic< int > g_scan_progress
RAII object to prevent concurrency issue when scanning the txout set.
static CBlock GetBlockChecked(BlockManager &blockman, const CBlockIndex &blockindex)
Definition: blockchain.cpp:621
std::optional< int > GetPruneHeight(const BlockManager &blockman, const CChain &chain)
Return height of highest block that has been pruned, or std::nullopt if no blocks have been pruned.
Definition: blockchain.cpp:814
UniValue blockToJSON(BlockManager &blockman, const CBlock &block, const CBlockIndex &tip, const CBlockIndex &blockindex, TxVerbosity verbosity, const uint256 pow_limit)
Block description to JSON.
Definition: blockchain.cpp:179
RPCHelpMan getdeploymentinfo()
static RPCHelpMan getblockfilter()
static RPCHelpMan getbestblockhash()
Definition: blockchain.cpp:240
RPCHelpMan getblockchaininfo()
void ReconsiderBlock(ChainstateManager &chainman, uint256 block_hash)
static RPCHelpMan getchaintxstats()
UniValue CreateUTXOSnapshot(node::NodeContext &node, Chainstate &chainstate, AutoFile &afile, const fs::path &path, const fs::path &tmppath)
Test-only helper to create UTXO snapshots given a chainstate and a file handle.
static RPCHelpMan waitforblock()
Definition: blockchain.cpp:302
std::tuple< std::unique_ptr< CCoinsViewCursor >, CCoinsStats, const CBlockIndex * > PrepareUTXOSnapshot(Chainstate &chainstate, const std::function< void()> &interruption_point={}) EXCLUSIVE_LOCKS_REQUIRED(UniValue WriteUTXOSnapshot(Chainstate &chainstate, CCoinsViewCursor *pcursor, CCoinsStats *maybe_stats, const CBlockIndex *tip, AutoFile &afile, const fs::path &path, const fs::path &temppath, const std::function< void()> &interruption_point={})
UniValue blockheaderToJSON(const CBlockIndex &tip, const CBlockIndex &blockindex, const uint256 pow_limit)
Block header to JSON.
Definition: blockchain.cpp:149
static RPCHelpMan getblockfrompeer()
Definition: blockchain.cpp:451
static const auto scan_result_status_some
static RPCHelpMan getblockhash()
Definition: blockchain.cpp:506
void RegisterBlockchainRPCCommands(CRPCTable &t)
void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector< std::pair< CAmount, int64_t > > &scores, int64_t total_weight)
Used by getblockstats to get feerates at different percentiles by weight
static std::optional< kernel::CCoinsStats > GetUTXOStats(CCoinsView *view, node::BlockManager &blockman, kernel::CoinStatsHashType hash_type, const std::function< void()> &interruption_point={}, const CBlockIndex *pindex=nullptr, bool index_requested=true)
Calculate statistics about the unspent transaction output set.
Definition: blockchain.cpp:914
static RPCHelpMan gettxout()
static RPCHelpMan verifychain()
static std::atomic< bool > g_should_abort_scan
const std::vector< RPCResult > RPCHelpForChainstate
static const auto scan_action_arg_desc
static RPCHelpMan waitforblockheight()
Definition: blockchain.cpp:356
static const CBlockIndex * ParseHashOrHeight(const UniValue &param, ChainstateManager &chainman)
Definition: blockchain.cpp:121
static RPCHelpMan pruneblockchain()
Definition: blockchain.cpp:839
static RPCHelpMan getblockheader()
Definition: blockchain.cpp:535
static RPCHelpMan scanblocks()
static std::atomic< bool > g_scanfilter_in_progress
static RPCHelpMan dumptxoutset()
Serialize the UTXO set to a file for loading elsewhere.
static std::vector< uint8_t > GetRawBlockChecked(BlockManager &blockman, const CBlockIndex &blockindex)
Definition: blockchain.cpp:638
static RPCHelpMan getblockcount()
Definition: blockchain.cpp:219
static RPCHelpMan waitfornewblock()
Definition: blockchain.cpp:260
static const auto scan_result_status_none
static constexpr int NUM_GETBLOCKSTATS_PERCENTILES
Definition: blockchain.h:28
const std::string & BlockFilterTypeName(BlockFilterType filter_type)
Get the human-readable name for a filter type.
bool BlockFilterTypeByName(const std::string &name, BlockFilterType &filter_type)
Find a filter type by its human-readable name.
BlockFilterType
Definition: blockfilter.h:93
BlockFilterIndex * GetBlockFilterIndex(BlockFilterType filter_type)
Get a block filter index by type.
@ BLOCK_VALID_SCRIPTS
Scripts & signatures ok.
Definition: chain.h:115
@ BLOCK_VALID_TREE
All parent headers found, difficulty matches, timestamp >= median previous, checkpoint.
Definition: chain.h:97
@ BLOCK_HAVE_UNDO
undo data available in rev*.dat
Definition: chain.h:122
@ BLOCK_HAVE_DATA
full block available in blk*.dat
Definition: chain.h:121
@ BLOCK_FAILED_MASK
Definition: chain.h:127
@ BLOCK_HAVE_MASK
Definition: chain.h:123
static constexpr int64_t TIMESTAMP_WINDOW
Timestamp window used as a grace period by code that compares external timestamps (such as timestamps...
Definition: chain.h:37
#define LIST_CHAIN_NAMES
List of possible chain / network names
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:81
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: args.h:234
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:392
bool IsNull() const
Return true if the wrapped FILE* is nullptr, false otherwise.
Definition: streams.h:428
int fclose()
Definition: streams.h:409
Complete block filter struct as defined in BIP 157.
Definition: blockfilter.h:115
const std::vector< unsigned char > & GetEncodedFilter() const LIFETIMEBOUND
Definition: blockfilter.h:138
BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of bloc...
bool LookupFilterRange(int start_height, const CBlockIndex *stop_index, std::vector< BlockFilter > &filters_out) const
Get a range of filters between two heights on a chain.
bool LookupFilter(const CBlockIndex *block_index, BlockFilter &filter_out) const
Get a single filter by block.
bool LookupFilterHeader(const CBlockIndex *block_index, uint256 &header_out) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_headers_cache)
Get a single filter header by block.
BlockFiltersScanReserver()=default
Definition: block.h:69
std::vector< CTransactionRef > vtx
Definition: block.h:72
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:141
uint256 hashMerkleRoot
Definition: chain.h:188
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: chain.h:147
uint64_t m_chain_tx_count
(memory only) Number of transactions in the chain up to and including this block.
Definition: chain.h:176
CBlockHeader GetBlockHeader() const
Definition: chain.h:230
arith_uint256 nChainWork
(memory only) Total amount of work (expected number of hashes) in the chain up to and including this ...
Definition: chain.h:165
uint32_t nTime
Definition: chain.h:189
uint32_t nNonce
Definition: chain.h:191
uint256 GetBlockHash() const
Definition: chain.h:243
int64_t GetBlockTime() const
Definition: chain.h:266
int64_t GetMedianTimePast() const
Definition: chain.h:278
uint32_t nBits
Definition: chain.h:190
unsigned int nTx
Number of transactions in this block.
Definition: chain.h:170
bool IsValid(enum BlockStatus nUpTo=BLOCK_VALID_TRANSACTIONS) const EXCLUSIVE_LOCKS_REQUIRED(
Check whether this block index entry is valid up to the passed validity level.
Definition: chain.h:295
int32_t nVersion
block header
Definition: chain.h:187
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition: chain.cpp:120
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:153
FlatFilePos GetBlockPos() const EXCLUSIVE_LOCKS_REQUIRED(
Definition: chain.h:208
Undo information for a CBlock.
Definition: undo.h:63
std::vector< CTxUndo > vtxundo
Definition: undo.h:65
An in-memory indexed chain of blocks.
Definition: chain.h:417
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:433
CBlockIndex * Genesis() const
Returns the index entry for the genesis block of this chain, or nullptr if none.
Definition: chain.h:427
CBlockIndex * FindEarliestAtLeast(int64_t nTime, int height) const
Find the earliest block with timestamp equal or greater than the given time and height equal or great...
Definition: chain.cpp:71
int Height() const
Return the maximal height in the chain.
Definition: chain.h:462
const CBlockIndex * FindFork(const CBlockIndex *pindex) const
Find the last common block between this chain and a block index entry.
Definition: chain.cpp:60
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
Definition: chain.h:447
std::string GetChainTypeString() const
Return the chain type string.
Definition: chainparams.h:113
const MessageStartChars & MessageStart() const
Definition: chainparams.h:94
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:93
uint64_t PruneAfterHeight() const
Definition: chainparams.h:105
ChainType GetChainType() const
Return the chain type.
Definition: chainparams.h:115
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:363
uint256 GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:173
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: coins.cpp:66
Cursor for iterating over CoinsView state.
Definition: coins.h:235
virtual void Next()=0
virtual bool Valid() const =0
virtual bool GetKey(COutPoint &key) const =0
virtual bool GetValue(Coin &coin) const =0
std::unique_ptr< CCoinsViewCursor > Cursor() const override
Get a cursor to iterate over the whole state.
Definition: txdb.cpp:182
Abstract view on the open txout dataset.
Definition: coins.h:310
virtual uint256 GetBestBlock() const
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:17
CCoinsView that brings transactions from a mempool into view.
Definition: txmempool.h:925
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
GetCoin, returning whether it exists and is not spent.
Definition: txmempool.cpp:1027
Definition: net.h:1052
bool GetNetworkActive() const
Definition: net.h:1136
void SetNetworkActive(bool active)
Definition: net.cpp:3194
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:29
uint32_t n
Definition: transaction.h:32
Txid hash
Definition: transaction.h:31
RPC command dispatcher.
Definition: server.h:127
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:415
An input of a transaction.
Definition: transaction.h:67
CTxMemPoolEntry stores data about the corresponding transaction, as well as data about all in-mempool...
Definition: mempool_entry.h:66
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:304
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:390
CTransactionRef get(const uint256 &hash) const
Definition: txmempool.cpp:884
std::vector< CTxMemPoolEntryRef > entryAll() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: txmempool.cpp:851
bool isSpent(const COutPoint &outpoint) const
Definition: txmempool.cpp:419
An output of a transaction.
Definition: transaction.h:150
CScript scriptPubKey
Definition: transaction.h:153
CAmount nValue
Definition: transaction.h:152
Undo information for a CTransaction.
Definition: undo.h:53
RAII wrapper for VerifyDB: Verify consistency of the block and coin databases.
Definition: validation.h:414
VerifyDBResult VerifyDB(Chainstate &chainstate, const Consensus::Params &consensus_params, CCoinsView &coinsview, int nCheckLevel, int nCheckDepth) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Definition: validation.h:505
CChain m_chain
The current chain of blockheaders we consult and build on.
Definition: validation.h:585
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:611
void ForceFlushStateToDisk()
Unconditionally flush all changes to disk.
CCoinsViewDB & CoinsDB() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:619
ChainstateManager & m_chainman
The chainstate manager that owns this chainstate.
Definition: validation.h:545
node::BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all Chainstate instances.
Definition: validation.h:540
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:866
node::BlockMap & BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:1125
SnapshotCompletionResult MaybeCompleteSnapshotValidation() EXCLUSIVE_LOCKS_REQUIRED(const CBlockIndex *GetSnapshotBaseBlock() const EXCLUSIVE_LOCKS_REQUIRED(Chainstate ActiveChainstate)() const
Once the background validation chainstate has reached the height which is the base of the UTXO snapsh...
Definition: validation.h:1110
double GuessVerificationProgress(const CBlockIndex *pindex) const
Guess verification progress (as a fraction between 0.0=genesis and 1.0=current tip).
kernel::Notifications & GetNotifications() const
Definition: validation.h:981
bool IsInitialBlockDownload() const
Check whether we are doing an initial block download (synchronizing from disk or network)
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
Definition: validation.h:1001
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1113
VersionBitsCache m_versionbitscache
Track versionbit status.
Definition: validation.h:1134
const CChainParams & GetParams() const
Definition: validation.h:976
const Consensus::Params & GetConsensus() const
Definition: validation.h:977
util::Result< CBlockIndex * > ActivateSnapshot(AutoFile &coins_file, const node::SnapshotMetadata &metadata, bool in_memory)
Construct and activate a Chainstate on the basis of UTXO snapshot data.
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1111
Chainstate &InitializeChainstate(CTxMemPool *mempool) EXCLUSIVE_LOCKS_REQUIRED(std::vector< Chainstate * GetAll)()
Instantiate a new chainstate.
Definition: validation.h:1080
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1007
A UTXO entry.
Definition: coins.h:33
bool IsCoinBase() const
Definition: coins.h:57
CTxOut out
unspent transaction output
Definition: coins.h:36
uint32_t nHeight
at which height this containing transaction was included in the active block chain
Definition: coins.h:42
CoinsViewScanReserver()=default
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:147
std::unordered_set< Element, ByteVectorHash > ElementSet
Definition: blockfilter.h:32
RAII class that disables the network in its constructor and enables it in its destructor.
NetworkDisable(CConnman &connman)
CConnman & m_connman
virtual std::optional< std::string > FetchBlock(NodeId peer_id, const CBlockIndex &block_index)=0
Attempt to manually fetch block from a given peer.
auto Arg(std::string_view key) const
Helper to get a required or default-valued request argument.
Definition: util.h:441
RAII class that temporarily rolls back the local chain in it's constructor and rolls it forward again...
TemporaryRollback(ChainstateManager &chainman, const CBlockIndex &index)
const CBlockIndex & m_invalidate_index
ChainstateManager & m_chainman
void push_back(UniValue val)
Definition: univalue.cpp:104
const std::string & get_str() const
@ VNULL
Definition: univalue.h:24
@ VOBJ
Definition: univalue.h:24
@ VARR
Definition: univalue.h:24
bool isNull() const
Definition: univalue.h:79
size_t size() const
Definition: univalue.h:71
const std::vector< UniValue > & getValues() const
Int getInt() const
Definition: univalue.h:138
const UniValue & get_array() const
bool isNum() const
Definition: univalue.h:84
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:126
bool IsValid() const
Definition: validation.h:106
std::string ToString() const
Definition: validation.h:112
int StateSinceHeight(const CBlockIndex *pindexPrev, const Consensus::Params &params, Consensus::DeploymentPos pos) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get the block height at which the BIP9 deployment switched into the state for the block after pindexP...
static BIP9Stats Statistics(const CBlockIndex *pindex, const Consensus::Params &params, Consensus::DeploymentPos pos, std::vector< bool > *signalling_blocks=nullptr)
Get the numerical statistics for a given deployment for the signalling period that includes pindex.
ThresholdState State(const CBlockIndex *pindexPrev, const Consensus::Params &params, Consensus::DeploymentPos pos) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get the BIP9 state for a given deployment for the block after pindexPrev.
std::string ToString() const
Definition: uint256.cpp:47
std::string GetHex() const
Definition: uint256.cpp:11
std::string GetHex() const
Hex encoding of the number (with the most significant digits first).
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:33
std::string utf8string() const
Return a UTF-8 representation of the path as a std::string, for compatibility with code using std::st...
Definition: fs.h:63
Interface giving clients (RPC, Stratum v2 Template Provider in the future) ability to create block te...
Definition: mining.h:64
virtual std::optional< BlockRef > getTip()=0
Returns the hash and height for the tip of this chain.
virtual BlockRef waitTipChanged(uint256 current_tip, MillisecondsDouble timeout=MillisecondsDouble::max())=0
Waits for the connected tip to change.
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
Definition: blockstorage.h:139
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
bool ReadBlockUndo(CBlockUndo &blockundo, const CBlockIndex &index) const
bool ReadRawBlock(std::vector< uint8_t > &block, const FlatFilePos &pos) const
uint64_t GetPruneTarget() const
Attempt to stay below this number of bytes of block files.
Definition: blockstorage.h:352
uint64_t CalculateCurrentUsage()
Calculate the amount of disk space the block & undo files currently use.
bool IsPruneMode() const
Whether running in -prune mode.
Definition: blockstorage.h:349
bool ReadBlock(CBlock &block, const FlatFilePos &pos) const
Functions for disk access for blocks.
Metadata describing a serialized version of a UTXO set from which an assumeutxo Chainstate can be con...
Definition: utxo_snapshot.h:34
constexpr const std::byte * begin() const
std::string GetHex() const
static transaction_identifier FromUint256(const uint256 &id)
256-bit opaque blob.
Definition: uint256.h:201
std::unique_ptr< CoinStatsIndex > g_coin_stats_index
The global UTXO set hash object.
static int64_t GetBlockWeight(const CBlock &block)
Definition: validation.h:137
static int32_t GetTransactionWeight(const CTransaction &tx)
Definition: validation.h:133
static const unsigned int MAX_BLOCK_SERIALIZED_SIZE
The maximum allowed size for a serialized block, in bytes (only for buffer size limits)
Definition: consensus.h:13
static const int WITNESS_SCALE_FACTOR
Definition: consensus.h:21
void TxToUniv(const CTransaction &tx, const uint256 &block_hash, UniValue &entry, bool include_hex=true, const CTxUndo *txundo=nullptr, TxVerbosity verbosity=TxVerbosity::SHOW_DETAILS)
Definition: core_write.cpp:171
TxVerbosity
Verbose level for block's transaction.
Definition: core_io.h:28
@ SHOW_DETAILS_AND_PREVOUT
The same as previous option with information about prevouts if available.
@ SHOW_TXID
Only TXID for each block's transaction.
@ SHOW_DETAILS
Include TXID, inputs, outputs, and other common block's transaction information.
void ScriptToUniv(const CScript &script, UniValue &out, bool include_hex=true, bool include_address=false, const SigningProvider *provider=nullptr)
Definition: core_write.cpp:150
UniValue ValueFromAmount(const CAmount amount)
Definition: core_write.cpp:26
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:8
std::string DeploymentName(Consensus::BuriedDeployment dep)
bool DeploymentActiveAfter(const CBlockIndex *pindexPrev, const Consensus::Params &params, Consensus::BuriedDeployment dep, VersionBitsCache &versionbitscache)
Determine if a deployment is active for the next block.
bool DeploymentEnabled(const Consensus::Params &params, Consensus::BuriedDeployment dep)
Determine if a deployment is enabled (can ever be active)
const std::string CURRENCY_UNIT
Definition: feerate.h:17
#define T(expected, seed, data)
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition: hex_base.cpp:29
#define LogWarning(...)
Definition: logging.h:262
#define LogDebug(category,...)
Definition: logging.h:280
unsigned int nHeight
static void pool cs
@ RPC
Definition: logging.h:50
@ NONE
Definition: logging.h:42
DeploymentPos
Definition: params.h:32
@ DEPLOYMENT_TAPROOT
Definition: params.h:34
@ DEPLOYMENT_TESTDUMMY
Definition: params.h:33
BuriedDeployment
A buried deployment is one where the height of the activation has been hardcoded into the client impl...
Definition: params.h:22
@ DEPLOYMENT_DERSIG
Definition: params.h:26
@ DEPLOYMENT_CSV
Definition: params.h:27
@ DEPLOYMENT_SEGWIT
Definition: params.h:28
@ DEPLOYMENT_HEIGHTINCB
Definition: params.h:24
@ DEPLOYMENT_CLTV
Definition: params.h:25
static path u8path(const std::string &utf8_str)
Definition: fs.h:75
static bool exists(const path &p)
Definition: fs.h:89
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:151
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:26
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:36
static bool ComputeUTXOStats(CCoinsView *view, CCoinsStats &stats, T hash_obj, const std::function< void()> &interruption_point)
Calculate statistics about the unspent transaction output set.
Definition: coinstats.cpp:116
CoinStatsHashType
Definition: coinstats.h:26
Definition: messages.h:20
UniValue GetWarningsForRpc(const Warnings &warnings, bool use_deprecated)
RPC helper function that wraps warnings.GetMessages().
Definition: warnings.cpp:54
bilingual_str ErrorString(const Result< T > &result)
Definition: result.h:93
std::string MakeUnorderedList(const std::vector< std::string > &items)
Create an unordered multi-line list of items.
Definition: string.h:213
int64_t NodeId
Definition: net.h:97
static constexpr TransactionSerParams TX_NO_WITNESS
Definition: transaction.h:196
static constexpr TransactionSerParams TX_WITH_WITNESS
Definition: transaction.h:195
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:423
@ NODE_NETWORK_LIMITED
Definition: protocol.h:327
@ NODE_NETWORK
Definition: protocol.h:315
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:70
@ RPC_MISC_ERROR
General application defined errors.
Definition: protocol.h:40
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:44
@ RPC_INTERNAL_ERROR
Definition: protocol.h:36
@ RPC_DATABASE_ERROR
Database error.
Definition: protocol.h:45
@ RPC_DESERIALIZATION_ERROR
Error parsing or validating structure in raw format.
Definition: protocol.h:46
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:42
std::vector< CScript > EvalDescriptorStringOrObject(const UniValue &scanobject, FlatSigningProvider &provider, const bool expand_priv)
Evaluate a descriptor given as a string, or as a {"desc":...,"range":...} object, with default range ...
Definition: util.cpp:1347
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:186
uint256 GetTarget(const CBlockIndex &blockindex, const uint256 pow_limit)
Definition: util.cpp:1424
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:204
const std::string UNIX_EPOCH_TIME
String used to describe UNIX epoch time in documentation, factored out to a constant for consistency.
Definition: util.cpp:46
std::string GetAllOutputTypes()
Gets all existing output types formatted for RPC help sections.
Definition: util.cpp:49
int ParseVerbosity(const UniValue &arg, int default_verbosity, bool allow_bool)
Parses verbosity from provided UniValue.
Definition: util.cpp:86
uint256 ParseHashV(const UniValue &v, std::string_view name)
Utilities: convert hex-encoded Values (throws error if not hex).
Definition: util.cpp:120
std::vector< RPCResult > ScriptPubKeyDoc()
Definition: util.cpp:1413
std::unique_ptr< Descriptor > InferDescriptor(const CScript &script, const SigningProvider &provider)
Find a descriptor for the specified script, using information from provider where possible.
size_t GetSerializeSize(const T &t)
Definition: serialize.h:1103
void WriteCompactSize(SizeComputer &os, uint64_t nSize)
Definition: serialize.h:1097
bool IsDeprecatedRPCEnabled(const std::string &method)
Definition: server.cpp:341
bool IsRPCRunning()
Query whether RPC is running.
Definition: server.cpp:310
ChainstateManager & EnsureAnyChainman(const std::any &context)
Definition: server_util.cpp:82
NodeContext & EnsureAnyNodeContext(const std::any &context)
Definition: server_util.cpp:25
CTxMemPool & EnsureMemPool(const NodeContext &node)
Definition: server_util.cpp:34
PeerManager & EnsurePeerman(const NodeContext &node)
ChainstateManager & EnsureChainman(const NodeContext &node)
Definition: server_util.cpp:74
ArgsManager & EnsureArgsman(const NodeContext &node)
Definition: server_util.cpp:61
interfaces::Mining & EnsureMining(const NodeContext &node)
CConnman & EnsureConnman(const NodeContext &node)
ArgsManager & EnsureAnyArgsman(const std::any &context)
Definition: server_util.cpp:69
unsigned char * UCharCast(char *c)
Definition: span.h:280
Display status of an in-progress BIP9 softfork.
Definition: versionbits.h:41
int count
Number of blocks with the version bit set since the beginning of the current period.
Definition: versionbits.h:49
int elapsed
Number of blocks elapsed since the beginning of the current period.
Definition: versionbits.h:47
int threshold
Number of blocks with the version bit set required to activate the softfork.
Definition: versionbits.h:45
bool possible
False if there are not enough blocks left in this period to pass activation threshold.
Definition: versionbits.h:51
int period
Length of blocks of the BIP9 signalling period.
Definition: versionbits.h:43
Comparison function for sorting the getchaintips heads.
bool operator()(const CBlockIndex *a, const CBlockIndex *b) const
int min_activation_height
If lock in occurs, delay activation until at least this block height.
Definition: params.h:54
int bit
Bit position to select the particular bit in nVersion.
Definition: params.h:45
int64_t nTimeout
Timeout/expiry MedianTime for the deployment attempt.
Definition: params.h:49
int64_t nStartTime
Start MedianTime for version bits miner confirmation.
Definition: params.h:47
std::vector< uint8_t > signet_challenge
Definition: params.h:134
BIP9Deployment vDeployments[MAX_VERSION_BITS_DEPLOYMENTS]
Definition: params.h:107
uint256 powLimit
Proof of work parameters.
Definition: params.h:109
int DeploymentHeight(BuriedDeployment dep) const
Definition: params.h:136
int64_t nPowTargetSpacing
Definition: params.h:117
Definition: util.h:183
@ RANGE
Special type that is a NUM or [NUM,NUM].
@ STR_HEX
Special type that is a STR with only hex chars.
@ OBJ_NAMED_PARAMS
Special type that behaves almost exactly like OBJ, defining an options object with a list of pre-defi...
std::string DefaultHint
Hint for default value.
Definition: util.h:217
@ OMITTED
Optional argument for which the default value is omitted from help text for one of two reasons:
@ NO
Required arg.
UniValue Default
Default constant value.
Definition: util.h:219
std::string oneline_description
Should be empty unless it is supposed to override the auto-generated summary line.
Definition: util.h:168
bool skip_type_check
Definition: util.h:167
@ ELISION
Special type to denote elision (...)
@ NUM_TIME
Special numeric to denote unix epoch time.
@ ARR_FIXED
Special array that has a fixed number of entries.
@ OBJ_DYN
Special dictionary with keys that are not literals.
@ STR_HEX
Special string with only hex chars.
@ STR_AMOUNT
Special string to represent a floating point amount.
std::optional< CAmount > total_amount
The total amount, or nullopt if an overflow occurred calculating it.
Definition: coinstats.h:41
uint64_t nDiskSize
Definition: coinstats.h:39
CAmount total_unspendable_amount
Total cumulative amount of unspendable coins up to and including this block.
Definition: coinstats.h:54
CAmount total_unspendables_scripts
Total cumulative amount of outputs sent to unspendable scripts (OP_RETURN for example) up to and incl...
Definition: coinstats.h:66
uint64_t coins_count
The number of coins contained.
Definition: coinstats.h:44
CAmount total_new_outputs_ex_coinbase_amount
Total cumulative amount of outputs created up to and including this block.
Definition: coinstats.h:58
uint64_t nTransactions
Definition: coinstats.h:35
uint64_t nTransactionOutputs
Definition: coinstats.h:36
CAmount total_coinbase_amount
Total cumulative amount of coinbase outputs up to and including this block.
Definition: coinstats.h:60
uint64_t nBogoSize
Definition: coinstats.h:37
bool index_used
Signals if the coinstatsindex was used to retrieve the statistics.
Definition: coinstats.h:47
CAmount total_unspendables_bip30
The two unspendable coinbase outputs total amount caused by BIP30.
Definition: coinstats.h:64
CAmount total_unspendables_genesis_block
The unspendable coinbase amount from the genesis block.
Definition: coinstats.h:62
CAmount total_prevout_spent_amount
Total cumulative amount of prevouts spent up to and including this block.
Definition: coinstats.h:56
uint256 hashSerialized
Definition: coinstats.h:38
CAmount total_unspendables_unclaimed_rewards
Total cumulative amount of coins lost due to unclaimed miner rewards up to and including this block.
Definition: coinstats.h:68
NodeContext struct containing references to chain state and connection state.
Definition: context.h:56
#define AssertLockNotHeld(cs)
Definition: sync.h:147
#define LOCK(cs)
Definition: sync.h:257
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:301
static int count
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:49
std::chrono::duration< double, std::chrono::milliseconds::period > MillisecondsDouble
Definition: time.h:87
#define LOG_TIME_SECONDS(end_msg)
Definition: timer.h:107
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
consteval auto _(util::TranslatedLiteral str)
Definition: translation.h:79
static const uint32_t MEMPOOL_HEIGHT
Fake height value used in Coin to signify they are only in the memory pool (since 0....
Definition: txmempool.h:49
const UniValue NullUniValue
Definition: univalue.cpp:16
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams)
const std::vector< std::string > CHECKLEVEL_DOC
Documentation for argument 'checklevel'.
Definition: validation.cpp:99
void PruneBlockFilesManual(Chainstate &active_chainstate, int nManualPruneHeight)
Prune block files up to a given height.
AssertLockHeld(pool.cs)
bool IsBIP30Repeat(const CBlockIndex &block_index)
Identifies blocks that overwrote an existing coinbase output in the UTXO set (see BIP30)
static constexpr int DEFAULT_CHECKLEVEL
Definition: validation.h:70
static const unsigned int MIN_BLOCKS_TO_KEEP
Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ActiveChain().Tip() will not be pr...
Definition: validation.h:68
static const signed int DEFAULT_CHECKBLOCKS
Definition: validation.h:69
ThresholdState
BIP 9 defines a finite-state-machine to deploy a softfork in multiple stages.
Definition: versionbits.h:27