Bitcoin ABC 0.33.12
P2P Digital Currency
blockchain.cpp
Go to the documentation of this file.
1// Copyright (c) 2010 Satoshi Nakamoto
2// Copyright (c) 2009-2019 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
9#include <blockfilter.h>
10#include <chain.h>
11#include <chainparams.h>
12#include <clientversion.h>
13#include <coins.h>
14#include <common/args.h>
15#include <config.h>
16#include <consensus/amount.h>
17#include <consensus/params.h>
19#include <core_io.h>
20#include <hash.h>
23#include <logging/timer.h>
24#include <net.h>
25#include <net_processing.h>
26#include <node/blockstorage.h>
27#include <node/coinstats.h>
28#include <node/context.h>
29#include <node/utxo_snapshot.h>
31#include <rpc/server.h>
32#include <rpc/server_util.h>
33#include <rpc/util.h>
34#include <script/descriptor.h>
35#include <serialize.h>
36#include <streams.h>
37#include <txdb.h>
38#include <txmempool.h>
39#include <undo.h>
40#include <util/check.h>
41#include <util/fs.h>
42#include <util/strencodings.h>
43#include <util/string.h>
44#include <util/translation.h>
45#include <validation.h>
46#include <validationinterface.h>
47#include <warnings.h>
48
49#include <condition_variable>
50#include <cstdint>
51#include <memory>
52#include <mutex>
53#include <optional>
54
57
63
66 int height;
67};
68
70static std::condition_variable cond_blockchange;
72
73std::tuple<std::unique_ptr<CCoinsViewCursor>, CCoinsStats, const CBlockIndex *>
75 const std::function<void()> &interruption_point = {})
77
80 CCoinsStats *maybe_stats, const CBlockIndex *tip,
81 AutoFile &afile, const fs::path &path,
82 const fs::path &temppath,
83 const std::function<void()> &interruption_point = {});
84
88double GetDifficulty(const CBlockIndex &blockindex) {
89 int nShift = (blockindex.nBits >> 24) & 0xff;
90 double dDiff = double(0x0000ffff) / double(blockindex.nBits & 0x00ffffff);
91
92 while (nShift < 29) {
93 dDiff *= 256.0;
94 nShift++;
95 }
96 while (nShift > 29) {
97 dDiff /= 256.0;
98 nShift--;
99 }
100
101 return dDiff;
102}
103
105 const CBlockIndex &blockindex,
106 const CBlockIndex *&next) {
107 next = tip.GetAncestor(blockindex.nHeight + 1);
108 if (next && next->pprev == &blockindex) {
109 return tip.nHeight - blockindex.nHeight + 1;
110 }
111 next = nullptr;
112 return &blockindex == &tip ? 1 : -1;
113}
114
115static const CBlockIndex *ParseHashOrHeight(const UniValue &param,
116 ChainstateManager &chainman) {
118 CChain &active_chain = chainman.ActiveChain();
119
120 if (param.isNum()) {
121 const int height{param.getInt<int>()};
122 if (height < 0) {
123 throw JSONRPCError(
125 strprintf("Target block height %d is negative", height));
126 }
127 const int current_tip{active_chain.Height()};
128 if (height > current_tip) {
129 throw JSONRPCError(
131 strprintf("Target block height %d after current tip %d", height,
132 current_tip));
133 }
134
135 return active_chain[height];
136 } else {
137 const BlockHash hash{ParseHashV(param, "hash_or_height")};
138 const CBlockIndex *pindex = chainman.m_blockman.LookupBlockIndex(hash);
139
140 if (!pindex) {
141 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
142 }
143
144 return pindex;
145 }
146}
148 const CBlockIndex &blockindex) {
149 // Serialize passed information without accessing chain state of the active
150 // chain!
151 // 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("difficulty", GetDifficulty(blockindex));
168 result.pushKV("chainwork", blockindex.nChainWork.GetHex());
169 result.pushKV("nTx", blockindex.nTx);
170
171 if (blockindex.pprev) {
172 result.pushKV("previousblockhash",
173 blockindex.pprev->GetBlockHash().GetHex());
174 }
175 if (pnext) {
176 result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
177 }
178 return result;
179}
180
181UniValue blockToJSON(BlockManager &blockman, const CBlock &block,
182 const CBlockIndex &tip, const CBlockIndex &blockindex,
183 TxVerbosity verbosity) {
184 UniValue result = blockheaderToJSON(tip, blockindex);
185
186 result.pushKV("size", (int)::GetSerializeSize(block));
188 switch (verbosity) {
190 for (const CTransactionRef &tx : block.vtx) {
191 txs.push_back(tx->GetId().GetHex());
192 }
193 break;
194
197 CBlockUndo blockUndo;
198 const bool is_not_pruned{WITH_LOCK(
199 ::cs_main, return !blockman.IsBlockPruned(blockindex))};
200 const bool have_undo{is_not_pruned &&
201 blockman.ReadBlockUndo(blockUndo, blockindex)};
202 for (size_t i = 0; i < block.vtx.size(); ++i) {
203 const CTransactionRef &tx = block.vtx.at(i);
204 // coinbase transaction (i == 0) doesn't have undo data
205 const CTxUndo *txundo = (have_undo && i > 0)
206 ? &blockUndo.vtxundo.at(i - 1)
207 : nullptr;
209 TxToUniv(*tx, BlockHash(), objTx, true, txundo, verbosity);
210 txs.push_back(std::move(objTx));
211 }
212 break;
213 }
214
215 result.pushKV("tx", std::move(txs));
216
217 return result;
218}
219
221 return RPCHelpMan{
222 "getblockcount",
223 "Returns the height of the most-work fully-validated chain.\n"
224 "The genesis block has height 0.\n",
225 {},
226 RPCResult{RPCResult::Type::NUM, "", "The current block count"},
227 RPCExamples{HelpExampleCli("getblockcount", "") +
228 HelpExampleRpc("getblockcount", "")},
229 [&](const RPCHelpMan &self, const Config &config,
230 const JSONRPCRequest &request) -> UniValue {
231 ChainstateManager &chainman = EnsureAnyChainman(request.context);
232 LOCK(cs_main);
233 return chainman.ActiveHeight();
234 },
235 };
236}
237
239 return RPCHelpMan{
240 "getbestblockhash",
241 "Returns the hash of the best (tip) block in the "
242 "most-work fully-validated chain.\n",
243 {},
244 RPCResult{RPCResult::Type::STR_HEX, "", "the block hash, hex-encoded"},
245 RPCExamples{HelpExampleCli("getbestblockhash", "") +
246 HelpExampleRpc("getbestblockhash", "")},
247 [&](const RPCHelpMan &self, const Config &config,
248 const JSONRPCRequest &request) -> UniValue {
249 ChainstateManager &chainman = EnsureAnyChainman(request.context);
250 LOCK(cs_main);
251 return chainman.ActiveTip()->GetBlockHash().GetHex();
252 },
253 };
254}
255
257 if (pindex) {
259 latestblock.hash = pindex->GetBlockHash();
260 latestblock.height = pindex->nHeight;
261 }
262 cond_blockchange.notify_all();
263}
264
266 return RPCHelpMan{
267 "waitfornewblock",
268 "Waits for a specific new block and returns useful info about it.\n"
269 "\nReturns the current block on timeout or exit.\n",
270 {
271 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0},
272 "Time in milliseconds to wait for a response. 0 indicates no "
273 "timeout."},
274 },
276 "",
277 "",
278 {
279 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
280 {RPCResult::Type::NUM, "height", "Block height"},
281 }},
282 RPCExamples{HelpExampleCli("waitfornewblock", "1000") +
283 HelpExampleRpc("waitfornewblock", "1000")},
284 [&](const RPCHelpMan &self, const Config &config,
285 const JSONRPCRequest &request) -> UniValue {
286 int timeout = 0;
287 if (!request.params[0].isNull()) {
288 timeout = request.params[0].getInt<int>();
289 }
290
291 CUpdatedBlock block;
292 {
294 block = latestblock;
295 if (timeout) {
296 cond_blockchange.wait_for(
297 lock, std::chrono::milliseconds(timeout),
299 return latestblock.height != block.height ||
300 latestblock.hash != block.hash ||
301 !IsRPCRunning();
302 });
303 } else {
304 cond_blockchange.wait(
305 lock,
307 return latestblock.height != block.height ||
308 latestblock.hash != block.hash ||
309 !IsRPCRunning();
310 });
311 }
312 block = latestblock;
313 }
315 ret.pushKV("hash", block.hash.GetHex());
316 ret.pushKV("height", block.height);
317 return ret;
318 },
319 };
320}
321
323 return RPCHelpMan{
324 "waitforblock",
325 "Waits for a specific new block and returns useful info about it.\n"
326 "\nReturns the current block on timeout or exit.\n",
327 {
329 "Block hash to wait for."},
330 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0},
331 "Time in milliseconds to wait for a response. 0 indicates no "
332 "timeout."},
333 },
335 "",
336 "",
337 {
338 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
339 {RPCResult::Type::NUM, "height", "Block height"},
340 }},
341 RPCExamples{HelpExampleCli("waitforblock",
342 "\"0000000000079f8ef3d2c688c244eb7a4570b24c9"
343 "ed7b4a8c619eb02596f8862\" 1000") +
344 HelpExampleRpc("waitforblock",
345 "\"0000000000079f8ef3d2c688c244eb7a4570b24c9"
346 "ed7b4a8c619eb02596f8862\", 1000")},
347 [&](const RPCHelpMan &self, const Config &config,
348 const JSONRPCRequest &request) -> UniValue {
349 int timeout = 0;
350
351 BlockHash hash(ParseHashV(request.params[0], "blockhash"));
352
353 if (!request.params[1].isNull()) {
354 timeout = request.params[1].getInt<int>();
355 }
356
357 CUpdatedBlock block;
358 {
360 if (timeout) {
361 cond_blockchange.wait_for(
362 lock, std::chrono::milliseconds(timeout),
364 return latestblock.hash == hash || !IsRPCRunning();
365 });
366 } else {
367 cond_blockchange.wait(
368 lock,
370 return latestblock.hash == hash || !IsRPCRunning();
371 });
372 }
373 block = latestblock;
374 }
375
377 ret.pushKV("hash", block.hash.GetHex());
378 ret.pushKV("height", block.height);
379 return ret;
380 },
381 };
382}
383
385 return RPCHelpMan{
386 "waitforblockheight",
387 "Waits for (at least) block height and returns the height and "
388 "hash\nof the current tip.\n"
389 "\nReturns the current block on timeout or exit.\n",
390 {
392 "Block height to wait for."},
393 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0},
394 "Time in milliseconds to wait for a response. 0 indicates no "
395 "timeout."},
396 },
398 "",
399 "",
400 {
401 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
402 {RPCResult::Type::NUM, "height", "Block height"},
403 }},
404 RPCExamples{HelpExampleCli("waitforblockheight", "100 1000") +
405 HelpExampleRpc("waitforblockheight", "100, 1000")},
406 [&](const RPCHelpMan &self, const Config &config,
407 const JSONRPCRequest &request) -> UniValue {
408 int timeout = 0;
409
410 int height = request.params[0].getInt<int>();
411
412 if (!request.params[1].isNull()) {
413 timeout = request.params[1].getInt<int>();
414 }
415
416 CUpdatedBlock block;
417 {
419 if (timeout) {
420 cond_blockchange.wait_for(
421 lock, std::chrono::milliseconds(timeout),
423 return latestblock.height >= height ||
424 !IsRPCRunning();
425 });
426 } else {
427 cond_blockchange.wait(
428 lock,
430 return latestblock.height >= height ||
431 !IsRPCRunning();
432 });
433 }
434 block = latestblock;
435 }
437 ret.pushKV("hash", block.hash.GetHex());
438 ret.pushKV("height", block.height);
439 return ret;
440 },
441 };
442}
443
445 return RPCHelpMan{
446 "syncwithvalidationinterfacequeue",
447 "Waits for the validation interface queue to catch up on everything "
448 "that was there when we entered this function.\n",
449 {},
451 RPCExamples{HelpExampleCli("syncwithvalidationinterfacequeue", "") +
452 HelpExampleRpc("syncwithvalidationinterfacequeue", "")},
453 [&](const RPCHelpMan &self, const Config &config,
454 const JSONRPCRequest &request) -> UniValue {
455 NodeContext &node = EnsureAnyNodeContext(request.context);
456 CHECK_NONFATAL(node.validation_signals)
457 ->SyncWithValidationInterfaceQueue();
458 return UniValue::VNULL;
459 },
460 };
461}
462
464 return RPCHelpMan{
465 "getdifficulty",
466 "Returns the proof-of-work difficulty as a multiple of the minimum "
467 "difficulty.\n",
468 {},
470 "the proof-of-work difficulty as a multiple of the minimum "
471 "difficulty."},
472 RPCExamples{HelpExampleCli("getdifficulty", "") +
473 HelpExampleRpc("getdifficulty", "")},
474 [&](const RPCHelpMan &self, const Config &config,
475 const JSONRPCRequest &request) -> UniValue {
476 ChainstateManager &chainman = EnsureAnyChainman(request.context);
477 LOCK(cs_main);
478 return GetDifficulty(*CHECK_NONFATAL(chainman.ActiveTip()));
479 },
480 };
481}
482
484 return RPCHelpMan{
485 "getblockfrompeer",
486 "Attempt to fetch block from a given peer.\n"
487 "\nWe must have the header for this block, e.g. using submitheader.\n"
488 "The block will not have any undo data which can limit the usage of "
489 "the block data in a context where the undo data is needed.\n"
490 "Subsequent calls for the same block may cause the response from the "
491 "previous peer to be ignored.\n"
492 "Peers generally ignore requests for a stale block that they never "
493 "fully verified, or one that is more than a month old.\n"
494 "When a peer does not respond with a block, we will disconnect.\n"
495 "\nReturns an empty JSON object if the request was successfully "
496 "scheduled.",
497 {
499 "The block hash to try to fetch"},
501 "The peer to fetch it from (see getpeerinfo for peer IDs)"},
502 },
503 RPCResult{RPCResult::Type::OBJ, "", /*optional=*/false, "", {}},
504 RPCExamples{HelpExampleCli("getblockfrompeer",
505 "\"00000000c937983704a73af28acdec37b049d214a"
506 "dbda81d7e2a3dd146f6ed09\" 0") +
507 HelpExampleRpc("getblockfrompeer",
508 "\"00000000c937983704a73af28acdec37b049d214a"
509 "dbda81d7e2a3dd146f6ed09\" 0")},
510 [&](const RPCHelpMan &self, const Config &config,
511 const JSONRPCRequest &request) -> UniValue {
512 const NodeContext &node = EnsureAnyNodeContext(request.context);
514 PeerManager &peerman = EnsurePeerman(node);
515
516 const BlockHash block_hash{
517 ParseHashV(request.params[0], "blockhash")};
518 const NodeId peer_id{request.params[1].getInt<int64_t>()};
519
520 const CBlockIndex *const index = WITH_LOCK(
521 cs_main,
522 return chainman.m_blockman.LookupBlockIndex(block_hash););
523
524 if (!index) {
525 throw JSONRPCError(RPC_MISC_ERROR, "Block header missing");
526 }
527
528 if (WITH_LOCK(::cs_main, return index->nStatus.hasData())) {
529 throw JSONRPCError(RPC_MISC_ERROR, "Block already downloaded");
530 }
531
532 if (const auto err{peerman.FetchBlock(config, peer_id, *index)}) {
533 throw JSONRPCError(RPC_MISC_ERROR, err.value());
534 }
535 return UniValue::VOBJ;
536 },
537 };
538}
539
541 return RPCHelpMan{
542 "getblockhash",
543 "Returns hash of block in best-block-chain at height provided.\n",
544 {
546 "The height index"},
547 },
548 RPCResult{RPCResult::Type::STR_HEX, "", "The block hash"},
549 RPCExamples{HelpExampleCli("getblockhash", "1000") +
550 HelpExampleRpc("getblockhash", "1000")},
551 [&](const RPCHelpMan &self, const Config &config,
552 const JSONRPCRequest &request) -> UniValue {
553 ChainstateManager &chainman = EnsureAnyChainman(request.context);
554 LOCK(cs_main);
555 const CChain &active_chain = chainman.ActiveChain();
556
557 int nHeight = request.params[0].getInt<int>();
558 if (nHeight < 0 || nHeight > active_chain.Height()) {
560 "Block height out of range");
561 }
562
563 const CBlockIndex *pblockindex = active_chain[nHeight];
564 return pblockindex->GetBlockHash().GetHex();
565 },
566 };
567}
568
570 return RPCHelpMan{
571 "getblockheader",
572 "If verbose is false, returns a string that is serialized, hex-encoded "
573 "data for blockheader 'hash'.\n"
574 "If verbose is true, returns an Object with information about "
575 "blockheader <hash>.\n",
576 {
578 "The block hash"},
579 {"verbose", RPCArg::Type::BOOL, RPCArg::Default{true},
580 "true for a json object, false for the hex-encoded data"},
581 },
582 {
583 RPCResult{
584 "for verbose = true",
586 "",
587 "",
588 {
590 "the block hash (same as provided)"},
591 {RPCResult::Type::NUM, "confirmations",
592 "The number of confirmations, or -1 if the block is not "
593 "on the main chain"},
594 {RPCResult::Type::NUM, "height",
595 "The block height or index"},
596 {RPCResult::Type::NUM, "version", "The block version"},
597 {RPCResult::Type::STR_HEX, "versionHex",
598 "The block version formatted in hexadecimal"},
599 {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
601 "The block time expressed in " + UNIX_EPOCH_TIME},
602 {RPCResult::Type::NUM_TIME, "mediantime",
603 "The median block time expressed in " + UNIX_EPOCH_TIME},
604 {RPCResult::Type::NUM, "nonce", "The nonce"},
605 {RPCResult::Type::STR_HEX, "bits", "The bits"},
606 {RPCResult::Type::NUM, "difficulty", "The difficulty"},
607 {RPCResult::Type::STR_HEX, "chainwork",
608 "Expected number of hashes required to produce the "
609 "current chain"},
610 {RPCResult::Type::NUM, "nTx",
611 "The number of transactions in the block"},
612 {RPCResult::Type::STR_HEX, "previousblockhash",
613 /* optional */ true,
614 "The hash of the previous block (if available)"},
615 {RPCResult::Type::STR_HEX, "nextblockhash",
616 /* optional */ true,
617 "The hash of the next block (if available)"},
618 }},
619 RPCResult{"for verbose=false", RPCResult::Type::STR_HEX, "",
620 "A string that is serialized, hex-encoded data for block "
621 "'hash'"},
622 },
623 RPCExamples{HelpExampleCli("getblockheader",
624 "\"00000000c937983704a73af28acdec37b049d214a"
625 "dbda81d7e2a3dd146f6ed09\"") +
626 HelpExampleRpc("getblockheader",
627 "\"00000000c937983704a73af28acdec37b049d214a"
628 "dbda81d7e2a3dd146f6ed09\"")},
629 [&](const RPCHelpMan &self, const Config &config,
630 const JSONRPCRequest &request) -> UniValue {
631 BlockHash hash(ParseHashV(request.params[0], "hash"));
632
633 bool fVerbose = true;
634 if (!request.params[1].isNull()) {
635 fVerbose = request.params[1].get_bool();
636 }
637
638 const CBlockIndex *pblockindex;
639 const CBlockIndex *tip;
640 {
641 ChainstateManager &chainman =
642 EnsureAnyChainman(request.context);
643 LOCK(cs_main);
644 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
645 tip = chainman.ActiveTip();
646 }
647
648 if (!pblockindex) {
650 "Block not found");
651 }
652
653 if (!fVerbose) {
654 DataStream ssBlock{};
655 ssBlock << pblockindex->GetBlockHeader();
656 std::string strHex = HexStr(ssBlock);
657 return strHex;
658 }
659
660 return blockheaderToJSON(*tip, *pblockindex);
661 },
662 };
663}
664
666 const CBlockIndex &blockindex) {
667 CBlock block;
668 {
669 LOCK(cs_main);
670 if (blockman.IsBlockPruned(blockindex)) {
672 "Block not available (pruned data)");
673 }
674 }
675
676 if (!blockman.ReadBlock(block, blockindex)) {
677 // Block not found on disk. This could be because we have the block
678 // header in our index but not yet have the block or did not accept the
679 // block. Or if the block was pruned right after we released the lock
680 // above.
681 throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
682 }
683
684 return block;
685}
686
688 const CBlockIndex &blockindex) {
689 CBlockUndo blockUndo;
690
691 {
692 LOCK(cs_main);
693 if (blockman.IsBlockPruned(blockindex)) {
695 "Undo data not available (pruned data)");
696 }
697 }
698
699 if (!blockman.ReadBlockUndo(blockUndo, blockindex)) {
700 throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
701 }
702
703 return blockUndo;
704}
705
707 return RPCHelpMan{
708 "getblock",
709 "If verbosity is 0 or false, returns a string that is serialized, "
710 "hex-encoded data for block 'hash'.\n"
711 "If verbosity is 1 or true, returns an Object with information about "
712 "block <hash>.\n"
713 "If verbosity is 2, returns an Object with information about block "
714 "<hash> and information about each transaction.\n"
715 "If verbosity is 3, returns an Object with information about block "
716 "<hash> and information about each transaction, including prevout "
717 "information for inputs (only for unpruned blocks in the current best "
718 "chain).\n",
719 {
721 "The block hash"},
722 {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1},
723 "0 for hex-encoded data, 1 for a json object, and 2 for json "
724 "object with transaction data",
726 },
727 {
728 RPCResult{"for verbosity = 0", RPCResult::Type::STR_HEX, "",
729 "A string that is serialized, hex-encoded data for block "
730 "'hash'"},
731 RPCResult{
732 "for verbosity = 1",
734 "",
735 "",
736 {
738 "the block hash (same as provided)"},
739 {RPCResult::Type::NUM, "confirmations",
740 "The number of confirmations, or -1 if the block is not "
741 "on the main chain"},
742 {RPCResult::Type::NUM, "size", "The block size"},
743 {RPCResult::Type::NUM, "height",
744 "The block height or index"},
745 {RPCResult::Type::NUM, "version", "The block version"},
746 {RPCResult::Type::STR_HEX, "versionHex",
747 "The block version formatted in hexadecimal"},
748 {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
750 "tx",
751 "The transaction ids",
752 {{RPCResult::Type::STR_HEX, "", "The transaction id"}}},
754 "The block time expressed in " + UNIX_EPOCH_TIME},
755 {RPCResult::Type::NUM_TIME, "mediantime",
756 "The median block time expressed in " + UNIX_EPOCH_TIME},
757 {RPCResult::Type::NUM, "nonce", "The nonce"},
758 {RPCResult::Type::STR_HEX, "bits", "The bits"},
759 {RPCResult::Type::NUM, "difficulty", "The difficulty"},
760 {RPCResult::Type::STR_HEX, "chainwork",
761 "Expected number of hashes required to produce the chain "
762 "up to this block (in hex)"},
763 {RPCResult::Type::NUM, "nTx",
764 "The number of transactions in the block"},
765 {RPCResult::Type::STR_HEX, "previousblockhash",
766 /* optional */ true,
767 "The hash of the previous block (if available)"},
768 {RPCResult::Type::STR_HEX, "nextblockhash",
769 /* optional */ true,
770 "The hash of the next block (if available)"},
771 }},
772 RPCResult{"for verbosity = 2",
774 "",
775 "",
776 {
778 "Same output as verbosity = 1"},
780 "tx",
781 "",
782 {
784 "",
785 "",
786 {
788 "The transactions in the format of the "
789 "getrawtransaction RPC. Different from "
790 "verbosity = 1 \"tx\" result"},
792 "The transaction fee in " +
794 ", omitted if block undo data is not "
795 "available"},
796 }},
797 }},
798 }},
799 },
801 HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d"
802 "214adbda81d7e2a3dd146f6ed09\"") +
803 HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d"
804 "214adbda81d7e2a3dd146f6ed09\"")},
805 [&](const RPCHelpMan &self, const Config &config,
806 const JSONRPCRequest &request) -> UniValue {
807 BlockHash hash(ParseHashV(request.params[0], "blockhash"));
808
809 int verbosity = 1;
810 if (!request.params[1].isNull()) {
811 if (request.params[1].isNum()) {
812 verbosity = request.params[1].getInt<int>();
813 } else {
814 verbosity = request.params[1].get_bool() ? 1 : 0;
815 }
816 }
817
818 const CBlockIndex *pblockindex;
819 const CBlockIndex *tip;
820 ChainstateManager &chainman = EnsureAnyChainman(request.context);
821 {
822 LOCK(cs_main);
823 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
824 tip = chainman.ActiveTip();
825
826 if (!pblockindex) {
828 "Block not found");
829 }
830 }
831
832 const CBlock block =
833 GetBlockChecked(chainman.m_blockman, *pblockindex);
834
835 if (verbosity <= 0) {
836 DataStream ssBlock{};
837 ssBlock << block;
838 std::string strHex = HexStr(ssBlock);
839 return strHex;
840 }
841
842 TxVerbosity tx_verbosity;
843 if (verbosity == 1) {
844 tx_verbosity = TxVerbosity::SHOW_TXID;
845 } else if (verbosity == 2) {
846 tx_verbosity = TxVerbosity::SHOW_DETAILS;
847 } else {
849 }
850
851 return blockToJSON(chainman.m_blockman, block, *tip, *pblockindex,
852 tx_verbosity);
853 },
854 };
855}
856
857std::optional<int> GetPruneHeight(const BlockManager &blockman,
858 const CChain &chain) {
860
861 // Search for the last block missing block data or undo data. Don't let the
862 // search consider the genesis block, because the genesis block does not
863 // have undo data, but should not be considered pruned.
864 const CBlockIndex *first_block{chain[1]};
865 const CBlockIndex *chain_tip{chain.Tip()};
866
867 // If there are no blocks after the genesis block, or no blocks at all,
868 // nothing is pruned.
869 if (!first_block || !chain_tip) {
870 return std::nullopt;
871 }
872
873 // If the chain tip is pruned, everything is pruned.
874 if (!(chain_tip->nStatus.hasData() && chain_tip->nStatus.hasUndo())) {
875 return chain_tip->nHeight;
876 }
877
878 // Get first block with data, after the last block without data.
879 // This is the start of the unpruned range of blocks.
880 const CBlockIndex *first_unpruned{CHECK_NONFATAL(
881 blockman.GetFirstBlock(*chain_tip,
882 /*status_test=*/[](const BlockStatus &status) {
883 return status.hasData() && status.hasUndo();
884 }))};
885 if (first_unpruned == first_block) {
886 // All blocks between first_block and chain_tip have data, so nothing is
887 // pruned.
888 return std::nullopt;
889 }
890
891 // Block before the first unpruned block is the last pruned block.
892 return CHECK_NONFATAL(first_unpruned->pprev)->nHeight;
893}
894
896 return RPCHelpMan{
897 "pruneblockchain",
898 "",
899 {
901 "The block height to prune up to. May be set to a discrete "
902 "height, or to a " +
904 "\n"
905 " to prune blocks whose block time is at "
906 "least 2 hours older than the provided timestamp."},
907 },
908 RPCResult{RPCResult::Type::NUM, "", "Height of the last block pruned"},
909 RPCExamples{HelpExampleCli("pruneblockchain", "1000") +
910 HelpExampleRpc("pruneblockchain", "1000")},
911 [&](const RPCHelpMan &self, const Config &config,
912 const JSONRPCRequest &request) -> UniValue {
913 ChainstateManager &chainman = EnsureAnyChainman(request.context);
914 if (!chainman.m_blockman.IsPruneMode()) {
915 throw JSONRPCError(
917 "Cannot prune blocks because node is not in prune mode.");
918 }
919
920 LOCK(cs_main);
921 Chainstate &active_chainstate = chainman.ActiveChainstate();
922 CChain &active_chain = active_chainstate.m_chain;
923
924 int heightParam = request.params[0].getInt<int>();
925 if (heightParam < 0) {
927 "Negative block height.");
928 }
929
930 // Height value more than a billion is too high to be a block
931 // height, and too low to be a block time (corresponds to timestamp
932 // from Sep 2001).
933 if (heightParam > 1000000000) {
934 // Add a 2 hour buffer to include blocks which might have had
935 // old timestamps
936 const CBlockIndex *pindex = active_chain.FindEarliestAtLeast(
937 heightParam - TIMESTAMP_WINDOW, 0);
938 if (!pindex) {
940 "Could not find block with at least the "
941 "specified timestamp.");
942 }
943 heightParam = pindex->nHeight;
944 }
945
946 unsigned int height = (unsigned int)heightParam;
947 unsigned int chainHeight = (unsigned int)active_chain.Height();
948 if (chainHeight < config.GetChainParams().PruneAfterHeight()) {
950 "Blockchain is too short for pruning.");
951 } else if (height > chainHeight) {
952 throw JSONRPCError(
954 "Blockchain is shorter than the attempted prune height.");
955 } else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
957 "Attempt to prune blocks close to the tip. "
958 "Retaining the minimum number of blocks.\n");
959 height = chainHeight - MIN_BLOCKS_TO_KEEP;
960 }
961
962 PruneBlockFilesManual(active_chainstate, height);
963 return GetPruneHeight(chainman.m_blockman, active_chain)
964 .value_or(-1);
965 },
966 };
967}
968
969static CoinStatsHashType ParseHashType(const std::string &hash_type_input) {
970 if (hash_type_input == "hash_serialized") {
971 return CoinStatsHashType::HASH_SERIALIZED;
972 } else if (hash_type_input == "muhash") {
973 return CoinStatsHashType::MUHASH;
974 } else if (hash_type_input == "none") {
976 } else {
977 throw JSONRPCError(
979 strprintf("%s is not a valid hash_type", hash_type_input));
980 }
981}
982
984 return RPCHelpMan{
985 "gettxoutsetinfo",
986 "Returns statistics about the unspent transaction output set.\n"
987 "Note this call may take some time if you are not using "
988 "coinstatsindex.\n",
989 {
990 {"hash_type", RPCArg::Type::STR, RPCArg::Default{"hash_serialized"},
991 "Which UTXO set hash should be calculated. Options: "
992 "'hash_serialized' (the legacy algorithm), 'muhash', 'none'."},
994 "The block hash or height of the target height (only available "
995 "with coinstatsindex).",
997 .type_str = {"", "string or numeric"}}},
998 {"use_index", RPCArg::Type::BOOL, RPCArg::Default{true},
999 "Use coinstatsindex, if available."},
1000 },
1001 RPCResult{
1003 "",
1004 "",
1005 {
1006 {RPCResult::Type::NUM, "height",
1007 "The current block height (index)"},
1008 {RPCResult::Type::STR_HEX, "bestblock",
1009 "The hash of the block at the tip of the chain"},
1010 {RPCResult::Type::NUM, "txouts",
1011 "The number of unspent transaction outputs"},
1012 {RPCResult::Type::NUM, "bogosize",
1013 "Database-independent, meaningless metric indicating "
1014 "the UTXO set size"},
1015 {RPCResult::Type::STR_HEX, "hash_serialized",
1016 /* optional */ true,
1017 "The serialized hash (only present if 'hash_serialized' "
1018 "hash_type is chosen)"},
1019 {RPCResult::Type::STR_HEX, "muhash", /* optional */ true,
1020 "The serialized hash (only present if 'muhash' "
1021 "hash_type is chosen)"},
1022 {RPCResult::Type::NUM, "transactions",
1023 "The number of transactions with unspent outputs (not "
1024 "available when coinstatsindex is used)"},
1025 {RPCResult::Type::NUM, "disk_size",
1026 "The estimated size of the chainstate on disk (not "
1027 "available when coinstatsindex is used)"},
1028 {RPCResult::Type::STR_AMOUNT, "total_amount",
1029 "The total amount"},
1030 {RPCResult::Type::STR_AMOUNT, "total_unspendable_amount",
1031 "The total amount of coins permanently excluded from the UTXO "
1032 "set (only available if coinstatsindex is used)"},
1034 "block_info",
1035 "Info on amounts in the block at this block height (only "
1036 "available if coinstatsindex is used)",
1037 {{RPCResult::Type::STR_AMOUNT, "prevout_spent",
1038 "Total amount of all prevouts spent in this block"},
1039 {RPCResult::Type::STR_AMOUNT, "coinbase",
1040 "Coinbase subsidy amount of this block"},
1041 {RPCResult::Type::STR_AMOUNT, "new_outputs_ex_coinbase",
1042 "Total amount of new outputs created by this block"},
1043 {RPCResult::Type::STR_AMOUNT, "unspendable",
1044 "Total amount of unspendable outputs created in this block"},
1046 "unspendables",
1047 "Detailed view of the unspendable categories",
1048 {
1049 {RPCResult::Type::STR_AMOUNT, "genesis_block",
1050 "The unspendable amount of the Genesis block subsidy"},
1052 "Transactions overridden by duplicates (no longer "
1053 "possible with BIP30)"},
1054 {RPCResult::Type::STR_AMOUNT, "scripts",
1055 "Amounts sent to scripts that are unspendable (for "
1056 "example OP_RETURN outputs)"},
1057 {RPCResult::Type::STR_AMOUNT, "unclaimed_rewards",
1058 "Fee rewards that miners did not claim in their "
1059 "coinbase transaction"},
1060 }}}},
1061 }},
1063 HelpExampleCli("gettxoutsetinfo", "") +
1064 HelpExampleCli("gettxoutsetinfo", R"("none")") +
1065 HelpExampleCli("gettxoutsetinfo", R"("none" 1000)") +
1067 "gettxoutsetinfo",
1068 R"("none" '"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"')") +
1069 HelpExampleRpc("gettxoutsetinfo", "") +
1070 HelpExampleRpc("gettxoutsetinfo", R"("none")") +
1071 HelpExampleRpc("gettxoutsetinfo", R"("none", 1000)") +
1073 "gettxoutsetinfo",
1074 R"("none", "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09")")},
1075 [&](const RPCHelpMan &self, const Config &config,
1076 const JSONRPCRequest &request) -> UniValue {
1078
1079 const CBlockIndex *pindex{nullptr};
1080 const CoinStatsHashType hash_type{
1081 request.params[0].isNull()
1082 ? CoinStatsHashType::HASH_SERIALIZED
1083 : ParseHashType(request.params[0].get_str())};
1084 bool index_requested =
1085 request.params[2].isNull() || request.params[2].get_bool();
1086
1087 NodeContext &node = EnsureAnyNodeContext(request.context);
1089 Chainstate &active_chainstate = chainman.ActiveChainstate();
1090 active_chainstate.ForceFlushStateToDisk();
1091
1092 CCoinsView *coins_view;
1093 BlockManager *blockman;
1094 {
1095 LOCK(::cs_main);
1096 coins_view = &active_chainstate.CoinsDB();
1097 blockman = &active_chainstate.m_blockman;
1098 pindex = blockman->LookupBlockIndex(coins_view->GetBestBlock());
1099 }
1100
1101 if (!request.params[1].isNull()) {
1102 if (!g_coin_stats_index) {
1104 "Querying specific block heights "
1105 "requires coinstatsindex");
1106 }
1107
1108 if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1110 "hash_serialized hash type cannot be "
1111 "queried for a specific block");
1112 }
1113
1114 pindex = ParseHashOrHeight(request.params[1], chainman);
1115 }
1116
1117 if (index_requested && g_coin_stats_index) {
1118 if (!g_coin_stats_index->BlockUntilSyncedToCurrentChain()) {
1119 const IndexSummary summary{
1120 g_coin_stats_index->GetSummary()};
1121
1122 // If a specific block was requested and the index has
1123 // already synced past that height, we can return the data
1124 // already even though the index is not fully synced yet.
1125 if (pindex->nHeight > summary.best_block_height) {
1126 throw JSONRPCError(
1128 strprintf(
1129 "Unable to get data because coinstatsindex is "
1130 "still syncing. Current height: %d",
1131 summary.best_block_height));
1132 }
1133 }
1134 }
1135
1136 const std::optional<CCoinsStats> maybe_stats = GetUTXOStats(
1137 coins_view, *blockman, hash_type, node.rpc_interruption_point,
1138 pindex, index_requested);
1139 if (maybe_stats.has_value()) {
1140 const CCoinsStats &stats = maybe_stats.value();
1141 ret.pushKV("height", int64_t(stats.nHeight));
1142 ret.pushKV("bestblock", stats.hashBlock.GetHex());
1143 ret.pushKV("txouts", int64_t(stats.nTransactionOutputs));
1144 ret.pushKV("bogosize", int64_t(stats.nBogoSize));
1145 if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1146 ret.pushKV("hash_serialized",
1147 stats.hashSerialized.GetHex());
1148 }
1149 if (hash_type == CoinStatsHashType::MUHASH) {
1150 ret.pushKV("muhash", stats.hashSerialized.GetHex());
1151 }
1152 CHECK_NONFATAL(stats.total_amount.has_value());
1153 ret.pushKV("total_amount", stats.total_amount.value());
1154 if (!stats.index_used) {
1155 ret.pushKV("transactions",
1156 static_cast<int64_t>(stats.nTransactions));
1157 ret.pushKV("disk_size", stats.nDiskSize);
1158 } else {
1159 ret.pushKV("total_unspendable_amount",
1161
1162 CCoinsStats prev_stats{};
1163 if (pindex->nHeight > 0) {
1164 const std::optional<CCoinsStats> maybe_prev_stats =
1165 GetUTXOStats(coins_view, *blockman, hash_type,
1166 node.rpc_interruption_point,
1167 pindex->pprev, index_requested);
1168 if (!maybe_prev_stats) {
1170 "Unable to read UTXO set");
1171 }
1172 prev_stats = maybe_prev_stats.value();
1173 }
1174
1175 UniValue block_info(UniValue::VOBJ);
1176 block_info.pushKV(
1177 "prevout_spent",
1179 prev_stats.total_prevout_spent_amount);
1180 block_info.pushKV("coinbase",
1181 stats.total_coinbase_amount -
1182 prev_stats.total_coinbase_amount);
1183 block_info.pushKV(
1184 "new_outputs_ex_coinbase",
1186 prev_stats.total_new_outputs_ex_coinbase_amount);
1187 block_info.pushKV("unspendable",
1189 prev_stats.total_unspendable_amount);
1190
1191 UniValue unspendables(UniValue::VOBJ);
1192 unspendables.pushKV(
1193 "genesis_block",
1195 prev_stats.total_unspendables_genesis_block);
1196 unspendables.pushKV(
1197 "bip30", stats.total_unspendables_bip30 -
1198 prev_stats.total_unspendables_bip30);
1199 unspendables.pushKV(
1200 "scripts", stats.total_unspendables_scripts -
1201 prev_stats.total_unspendables_scripts);
1202 unspendables.pushKV(
1203 "unclaimed_rewards",
1205 prev_stats.total_unspendables_unclaimed_rewards);
1206 block_info.pushKV("unspendables", std::move(unspendables));
1207
1208 ret.pushKV("block_info", std::move(block_info));
1209 }
1210 } else {
1212 "Unable to read UTXO set");
1213 }
1214 return ret;
1215 },
1216 };
1217}
1218
1220 return RPCHelpMan{
1221 "gettxout",
1222 "Returns details about an unspent transaction output.\n",
1223 {
1225 "The transaction id"},
1226 {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
1227 {"include_mempool", RPCArg::Type::BOOL, RPCArg::Default{true},
1228 "Whether to include the mempool. Note that an unspent output that "
1229 "is spent in the mempool won't appear."},
1230 },
1231 {
1232 RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "",
1233 ""},
1234 RPCResult{
1235 "Otherwise",
1237 "",
1238 "",
1239 {
1240 {RPCResult::Type::STR_HEX, "bestblock",
1241 "The hash of the block at the tip of the chain"},
1242 {RPCResult::Type::NUM, "confirmations",
1243 "The number of confirmations"},
1245 "The transaction value in " + Currency::getTicker()},
1247 "scriptPubKey",
1248 "",
1249 {
1250 {RPCResult::Type::STR_HEX, "asm", ""},
1251 {RPCResult::Type::STR_HEX, "hex", ""},
1252 {RPCResult::Type::NUM, "reqSigs",
1253 "Number of required signatures"},
1254 {RPCResult::Type::STR_HEX, "type",
1255 "The type, eg pubkeyhash"},
1257 "addresses",
1258 "array of eCash addresses",
1259 {{RPCResult::Type::STR, "address", "eCash address"}}},
1260 }},
1261 {RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
1262 }},
1263 },
1264 RPCExamples{"\nGet unspent transactions\n" +
1265 HelpExampleCli("listunspent", "") + "\nView the details\n" +
1266 HelpExampleCli("gettxout", "\"txid\" 1") +
1267 "\nAs a JSON-RPC call\n" +
1268 HelpExampleRpc("gettxout", "\"txid\", 1")},
1269 [&](const RPCHelpMan &self, const Config &config,
1270 const JSONRPCRequest &request) -> UniValue {
1271 NodeContext &node = EnsureAnyNodeContext(request.context);
1273 LOCK(cs_main);
1274
1276
1277 TxId txid(ParseHashV(request.params[0], "txid"));
1278 int n = request.params[1].getInt<int>();
1279 COutPoint out(txid, n);
1280 bool fMempool = true;
1281 if (!request.params[2].isNull()) {
1282 fMempool = request.params[2].get_bool();
1283 }
1284
1285 Chainstate &active_chainstate = chainman.ActiveChainstate();
1286 CCoinsViewCache *coins_view = &active_chainstate.CoinsTip();
1287
1288 std::optional<Coin> coin;
1289 if (fMempool) {
1290 const CTxMemPool &mempool = EnsureMemPool(node);
1291 LOCK(mempool.cs);
1292 CCoinsViewMemPool view(coins_view, mempool);
1293 if (!mempool.isSpent(out)) {
1294 coin = view.GetCoin(out);
1295 }
1296 } else {
1297 coin = coins_view->GetCoin(out);
1298 }
1299 if (!coin) {
1300 return UniValue::VNULL;
1301 }
1302
1303 const CBlockIndex *pindex =
1304 active_chainstate.m_blockman.LookupBlockIndex(
1305 coins_view->GetBestBlock());
1306 ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
1307 if (coin->GetHeight() == MEMPOOL_HEIGHT) {
1308 ret.pushKV("confirmations", 0);
1309 } else {
1310 ret.pushKV("confirmations",
1311 int64_t(pindex->nHeight - coin->GetHeight() + 1));
1312 }
1313 ret.pushKV("value", coin->GetTxOut().nValue);
1315 ScriptPubKeyToUniv(coin->GetTxOut().scriptPubKey, o, true);
1316 ret.pushKV("scriptPubKey", std::move(o));
1317 ret.pushKV("coinbase", coin->IsCoinBase());
1318
1319 return ret;
1320 },
1321 };
1322}
1323
1325 return RPCHelpMan{
1326 "verifychain",
1327 "Verifies blockchain database.\n",
1328 {
1329 {"checklevel", RPCArg::Type::NUM,
1331 strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL)},
1332 strprintf("How thorough the block verification is:\n%s",
1334 {"nblocks", RPCArg::Type::NUM,
1336 "The number of blocks to check."},
1337 },
1339 "Verification finished successfully. If false, check "
1340 "debug.log for reason."},
1341 RPCExamples{HelpExampleCli("verifychain", "") +
1342 HelpExampleRpc("verifychain", "")},
1343 [&](const RPCHelpMan &self, const Config &config,
1344 const JSONRPCRequest &request) -> UniValue {
1345 const int check_level{request.params[0].isNull()
1347 : request.params[0].getInt<int>()};
1348 const int check_depth{request.params[1].isNull()
1350 : request.params[1].getInt<int>()};
1351
1352 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1353 LOCK(cs_main);
1354
1355 Chainstate &active_chainstate = chainman.ActiveChainstate();
1356 return CVerifyDB(chainman.GetNotifications())
1357 .VerifyDB(active_chainstate,
1358 active_chainstate.CoinsTip(), check_level,
1359 check_depth) == VerifyDBResult::SUCCESS;
1360 },
1361 };
1362}
1363
1365 return RPCHelpMan{
1366 "getblockchaininfo",
1367 "Returns an object containing various state info regarding blockchain "
1368 "processing.\n",
1369 {},
1370 RPCResult{
1372 "",
1373 "",
1374 {
1375 {RPCResult::Type::STR, "chain",
1376 "current network name (main, test, regtest)"},
1377 {RPCResult::Type::NUM, "blocks",
1378 "the height of the most-work fully-validated "
1379 "non-parked chain. The genesis block has height 0"},
1380 {RPCResult::Type::NUM, "headers",
1381 "the current number of headers we have validated"},
1382 {RPCResult::Type::NUM, "finalized_blockhash",
1383 "the hash of the avalanche finalized tip if any, otherwise "
1384 "the genesis block hash"},
1385 {RPCResult::Type::STR, "bestblockhash",
1386 "the hash of the currently best block"},
1387 {RPCResult::Type::NUM, "difficulty", "the current difficulty"},
1389 "The block time expressed in " + UNIX_EPOCH_TIME},
1390 {RPCResult::Type::NUM_TIME, "mediantime",
1391 "The median block time expressed in " + UNIX_EPOCH_TIME},
1392 {RPCResult::Type::NUM, "verificationprogress",
1393 "estimate of verification progress [0..1]"},
1394 {RPCResult::Type::BOOL, "initialblockdownload",
1395 "(debug information) estimate of whether this node is in "
1396 "Initial Block Download mode"},
1397 {RPCResult::Type::STR_HEX, "chainwork",
1398 "total amount of work in active chain, in hexadecimal"},
1399 {RPCResult::Type::NUM, "size_on_disk",
1400 "the estimated size of the block and undo files on disk"},
1401 {RPCResult::Type::BOOL, "pruned",
1402 "if the blocks are subject to pruning"},
1403 {RPCResult::Type::NUM, "pruneheight",
1404 "lowest-height complete block stored (only present if pruning "
1405 "is enabled)"},
1406 {RPCResult::Type::BOOL, "automatic_pruning",
1407 "whether automatic pruning is enabled (only present if "
1408 "pruning is enabled)"},
1409 {RPCResult::Type::NUM, "prune_target_size",
1410 "the target size used by pruning (only present if automatic "
1411 "pruning is enabled)"},
1412 {RPCResult::Type::STR, "warnings",
1413 "any network and blockchain warnings"},
1414 }},
1415 RPCExamples{HelpExampleCli("getblockchaininfo", "") +
1416 HelpExampleRpc("getblockchaininfo", "")},
1417 [&](const RPCHelpMan &self, const Config &config,
1418 const JSONRPCRequest &request) -> UniValue {
1419 const CChainParams &chainparams = config.GetChainParams();
1420
1421 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1422 LOCK(cs_main);
1423 Chainstate &active_chainstate = chainman.ActiveChainstate();
1424
1425 const CBlockIndex &tip{
1426 *CHECK_NONFATAL(active_chainstate.m_chain.Tip())};
1427 const int height{tip.nHeight};
1428
1430 obj.pushKV("chain", chainparams.GetChainTypeString());
1431 obj.pushKV("blocks", height);
1432 obj.pushKV("headers", chainman.m_best_header
1433 ? chainman.m_best_header->nHeight
1434 : -1);
1435 auto avalanche_finalized_tip{chainman.GetAvalancheFinalizedTip()};
1436 obj.pushKV("finalized_blockhash",
1437 avalanche_finalized_tip
1438 ? avalanche_finalized_tip->GetBlockHash().GetHex()
1439 : chainparams.GenesisBlock().GetHash().GetHex());
1440 obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex());
1441 obj.pushKV("difficulty", GetDifficulty(tip));
1442 obj.pushKV("time", tip.GetBlockTime());
1443 obj.pushKV("mediantime", tip.GetMedianTimePast());
1444 obj.pushKV(
1445 "verificationprogress",
1446 GuessVerificationProgress(chainman.GetParams().TxData(), &tip));
1447 obj.pushKV("initialblockdownload",
1448 chainman.IsInitialBlockDownload());
1449 obj.pushKV("chainwork", tip.nChainWork.GetHex());
1450 obj.pushKV("size_on_disk",
1452 obj.pushKV("pruned", chainman.m_blockman.IsPruneMode());
1453
1454 if (chainman.m_blockman.IsPruneMode()) {
1455 const auto prune_height{GetPruneHeight(
1456 chainman.m_blockman, active_chainstate.m_chain)};
1457 obj.pushKV("pruneheight",
1458 prune_height ? prune_height.value() + 1 : 0);
1459
1460 const bool automatic_pruning{
1461 chainman.m_blockman.GetPruneTarget() !=
1462 BlockManager::PRUNE_TARGET_MANUAL};
1463 obj.pushKV("automatic_pruning", automatic_pruning);
1464 if (automatic_pruning) {
1465 obj.pushKV("prune_target_size",
1466 chainman.m_blockman.GetPruneTarget());
1467 }
1468 }
1469
1470 obj.pushKV("warnings", GetWarnings(false).original);
1471 return obj;
1472 },
1473 };
1474}
1475
1478 bool operator()(const CBlockIndex *a, const CBlockIndex *b) const {
1479 // Make sure that unequal blocks with the same height do not compare
1480 // equal. Use the pointers themselves to make a distinction.
1481 if (a->nHeight != b->nHeight) {
1482 return (a->nHeight > b->nHeight);
1483 }
1484
1485 return a < b;
1486 }
1487};
1488
1490 return RPCHelpMan{
1491 "getchaintips",
1492 "Return information about all known tips in the block tree, including "
1493 "the main chain as well as orphaned branches.\n",
1494 {},
1495 RPCResult{
1497 "",
1498 "",
1500 "",
1501 "",
1502 {
1503 {RPCResult::Type::NUM, "height", "height of the chain tip"},
1504 {RPCResult::Type::STR_HEX, "hash", "block hash of the tip"},
1505 {RPCResult::Type::NUM, "branchlen",
1506 "zero for main chain, otherwise length of branch connecting "
1507 "the tip to the main chain"},
1508 {RPCResult::Type::STR, "status",
1509 "status of the chain, \"active\" for the main chain\n"
1510 "Possible values for status:\n"
1511 "1. \"invalid\" This branch contains at "
1512 "least one invalid block\n"
1513 "2. \"parked\" This branch contains at "
1514 "least one parked block\n"
1515 "3. \"headers-only\" Not all blocks for this "
1516 "branch are available, but the headers are valid\n"
1517 "4. \"valid-headers\" All blocks are available for "
1518 "this branch, but they were never fully validated\n"
1519 "5. \"valid-fork\" This branch is not part of "
1520 "the active chain, but is fully validated\n"
1521 "6. \"active\" This is the tip of the "
1522 "active main chain, which is certainly valid"},
1523 }}}},
1524 RPCExamples{HelpExampleCli("getchaintips", "") +
1525 HelpExampleRpc("getchaintips", "")},
1526 [&](const RPCHelpMan &self, const Config &config,
1527 const JSONRPCRequest &request) -> UniValue {
1528 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1529 LOCK(cs_main);
1530 CChain &active_chain = chainman.ActiveChain();
1531
1543 std::set<const CBlockIndex *, CompareBlocksByHeight> setTips;
1544 std::set<const CBlockIndex *> setOrphans;
1545 std::set<const CBlockIndex *> setPrevs;
1546
1547 for (const auto &[_, block_index] : chainman.BlockIndex()) {
1548 if (!active_chain.Contains(&block_index)) {
1549 setOrphans.insert(&block_index);
1550 setPrevs.insert(block_index.pprev);
1551 }
1552 }
1553
1554 for (std::set<const CBlockIndex *>::iterator it =
1555 setOrphans.begin();
1556 it != setOrphans.end(); ++it) {
1557 if (setPrevs.erase(*it) == 0) {
1558 setTips.insert(*it);
1559 }
1560 }
1561
1562 // Always report the currently active tip.
1563 setTips.insert(active_chain.Tip());
1564
1565 /* Construct the output array. */
1567 for (const CBlockIndex *block : setTips) {
1569 obj.pushKV("height", block->nHeight);
1570 obj.pushKV("hash", block->phashBlock->GetHex());
1571
1572 const int branchLen =
1573 block->nHeight - active_chain.FindFork(block)->nHeight;
1574 obj.pushKV("branchlen", branchLen);
1575
1576 std::string status;
1577 if (active_chain.Contains(block)) {
1578 // This block is part of the currently active chain.
1579 status = "active";
1580 } else if (block->nStatus.isInvalid()) {
1581 // This block or one of its ancestors is invalid.
1582 status = "invalid";
1583 } else if (block->nStatus.isOnParkedChain()) {
1584 // This block or one of its ancestors is parked.
1585 status = "parked";
1586 } else if (!block->HaveNumChainTxs()) {
1587 // This block cannot be connected because full block data
1588 // for it or one of its parents is missing.
1589 status = "headers-only";
1590 } else if (block->IsValid(BlockValidity::SCRIPTS)) {
1591 // This block is fully validated, but no longer part of the
1592 // active chain. It was probably the active block once, but
1593 // was reorganized.
1594 status = "valid-fork";
1595 } else if (block->IsValid(BlockValidity::TREE)) {
1596 // The headers for this block are valid, but it has not been
1597 // validated. It was probably never part of the most-work
1598 // chain.
1599 status = "valid-headers";
1600 } else {
1601 // No clue.
1602 status = "unknown";
1603 }
1604 obj.pushKV("status", status);
1605
1606 res.push_back(std::move(obj));
1607 }
1608
1609 return res;
1610 },
1611 };
1612}
1613
1615 return RPCHelpMan{
1616 "preciousblock",
1617 "Treats a block as if it were received before others with the same "
1618 "work.\n"
1619 "\nA later preciousblock call can override the effect of an earlier "
1620 "one.\n"
1621 "\nThe effects of preciousblock are not retained across restarts.\n",
1622 {
1624 "the hash of the block to mark as precious"},
1625 },
1627 RPCExamples{HelpExampleCli("preciousblock", "\"blockhash\"") +
1628 HelpExampleRpc("preciousblock", "\"blockhash\"")},
1629 [&](const RPCHelpMan &self, const Config &config,
1630 const JSONRPCRequest &request) -> UniValue {
1631 BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1632 CBlockIndex *pblockindex;
1633
1634 NodeContext &node = EnsureAnyNodeContext(request.context);
1636 {
1637 LOCK(cs_main);
1638 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1639 if (!pblockindex) {
1641 "Block not found");
1642 }
1643 }
1644
1646 chainman.ActiveChainstate().PreciousBlock(state, pblockindex,
1647 node.avalanche.get());
1648
1649 if (!state.IsValid()) {
1651 }
1652
1653 // Block to make sure wallet/indexers sync before returning
1654 CHECK_NONFATAL(node.validation_signals)
1655 ->SyncWithValidationInterfaceQueue();
1656
1657 return NullUniValue;
1658 },
1659 };
1660}
1661
1664 const BlockHash &block_hash) {
1666 CBlockIndex *pblockindex;
1667 {
1668 LOCK(chainman.GetMutex());
1669 pblockindex = chainman.m_blockman.LookupBlockIndex(block_hash);
1670 if (!pblockindex) {
1671 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1672 }
1673 }
1674 chainman.ActiveChainstate().InvalidateBlock(state, pblockindex);
1675
1676 if (state.IsValid()) {
1677 chainman.ActiveChainstate().ActivateBestChain(state, /*pblock=*/nullptr,
1678 avalanche);
1679 }
1680
1681 if (!state.IsValid()) {
1683 }
1684}
1685
1687 return RPCHelpMan{
1688 "invalidateblock",
1689 "Permanently marks a block as invalid, as if it violated a consensus "
1690 "rule.\n",
1691 {
1693 "the hash of the block to mark as invalid"},
1694 },
1696 RPCExamples{HelpExampleCli("invalidateblock", "\"blockhash\"") +
1697 HelpExampleRpc("invalidateblock", "\"blockhash\"")},
1698 [&](const RPCHelpMan &self, const Config &config,
1699 const JSONRPCRequest &request) -> UniValue {
1700 NodeContext &node = EnsureAnyNodeContext(request.context);
1702 const BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1703
1704 InvalidateBlock(chainman, node.avalanche.get(), hash);
1705 // Block to make sure wallet/indexers sync before returning
1706 CHECK_NONFATAL(node.validation_signals)
1707 ->SyncWithValidationInterfaceQueue();
1708
1709 return NullUniValue;
1710 },
1711 };
1712}
1713
1715 return RPCHelpMan{
1716 "parkblock",
1717 "Marks a block as parked.\n",
1718 {
1720 "the hash of the block to park"},
1721 },
1723 RPCExamples{HelpExampleCli("parkblock", "\"blockhash\"") +
1724 HelpExampleRpc("parkblock", "\"blockhash\"")},
1725 [&](const RPCHelpMan &self, const Config &config,
1726 const JSONRPCRequest &request) -> UniValue {
1727 const std::string strHash = request.params[0].get_str();
1728 const BlockHash hash(uint256S(strHash));
1730
1731 NodeContext &node = EnsureAnyNodeContext(request.context);
1733 Chainstate &active_chainstate = chainman.ActiveChainstate();
1734 CBlockIndex *pblockindex = nullptr;
1735 {
1736 LOCK(cs_main);
1737 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1738 if (!pblockindex) {
1740 "Block not found");
1741 }
1742
1743 if (active_chainstate.IsBlockAvalancheFinalized(pblockindex)) {
1744 // Reset avalanche finalization if we park a finalized
1745 // block.
1746 active_chainstate.ClearAvalancheFinalizedBlock();
1747 }
1748 }
1749
1750 active_chainstate.ParkBlock(state, pblockindex);
1751
1752 if (state.IsValid()) {
1753 active_chainstate.ActivateBestChain(state, /*pblock=*/nullptr,
1754 node.avalanche.get());
1755 }
1756
1757 if (!state.IsValid()) {
1759 }
1760
1761 // Block to make sure wallet/indexers sync before returning
1762 CHECK_NONFATAL(node.validation_signals)
1763 ->SyncWithValidationInterfaceQueue();
1764
1765 return NullUniValue;
1766 },
1767 };
1768}
1769
1772 const BlockHash &block_hash) {
1773 {
1774 LOCK(chainman.GetMutex());
1775 CBlockIndex *pblockindex =
1776 chainman.m_blockman.LookupBlockIndex(block_hash);
1777 if (!pblockindex) {
1778 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1779 }
1780
1781 chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex);
1782 chainman.RecalculateBestHeader();
1783 }
1784
1786 chainman.ActiveChainstate().ActivateBestChain(state, /*pblock=*/nullptr,
1787 avalanche);
1788
1789 if (!state.IsValid()) {
1791 }
1792}
1793
1795 return RPCHelpMan{
1796 "reconsiderblock",
1797 "Removes invalidity status of a block, its ancestors and its"
1798 "descendants, reconsider them for activation.\n"
1799 "This can be used to undo the effects of invalidateblock.\n",
1800 {
1802 "the hash of the block to reconsider"},
1803 },
1805 RPCExamples{HelpExampleCli("reconsiderblock", "\"blockhash\"") +
1806 HelpExampleRpc("reconsiderblock", "\"blockhash\"")},
1807 [&](const RPCHelpMan &self, const Config &config,
1808 const JSONRPCRequest &request) -> UniValue {
1809 NodeContext &node = EnsureAnyNodeContext(request.context);
1811 const BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1812
1813 ReconsiderBlock(chainman, node.avalanche.get(), hash);
1814
1815 // Block to make sure wallet/indexers sync before returning
1816 CHECK_NONFATAL(node.validation_signals)
1817 ->SyncWithValidationInterfaceQueue();
1818
1819 return NullUniValue;
1820 },
1821 };
1822}
1823
1825 return RPCHelpMan{
1826 "unparkblock",
1827 "Removes parked status of a block and its descendants, reconsider "
1828 "them for activation.\n"
1829 "This can be used to undo the effects of parkblock.\n",
1830 {
1832 "the hash of the block to unpark"},
1833 },
1835 RPCExamples{HelpExampleCli("unparkblock", "\"blockhash\"") +
1836 HelpExampleRpc("unparkblock", "\"blockhash\"")},
1837 [&](const RPCHelpMan &self, const Config &config,
1838 const JSONRPCRequest &request) -> UniValue {
1839 const std::string strHash = request.params[0].get_str();
1840 NodeContext &node = EnsureAnyNodeContext(request.context);
1842 const BlockHash hash(uint256S(strHash));
1843 Chainstate &active_chainstate = chainman.ActiveChainstate();
1844
1845 {
1846 LOCK(cs_main);
1847
1848 CBlockIndex *pblockindex =
1849 chainman.m_blockman.LookupBlockIndex(hash);
1850 if (!pblockindex) {
1852 "Block not found");
1853 }
1854
1855 if (!pblockindex->nStatus.isOnParkedChain()) {
1856 // Block to unpark is not parked so there is nothing to do.
1857 return NullUniValue;
1858 }
1859
1860 const CBlockIndex *tip = active_chainstate.m_chain.Tip();
1861 if (tip) {
1862 const CBlockIndex *ancestor =
1863 LastCommonAncestor(tip, pblockindex);
1864 if (active_chainstate.IsBlockAvalancheFinalized(ancestor)) {
1865 // Only reset avalanche finalization if we unpark a
1866 // block that might conflict with avalanche finalized
1867 // blocks.
1868 active_chainstate.ClearAvalancheFinalizedBlock();
1869 }
1870 }
1871
1872 active_chainstate.UnparkBlockAndChildren(pblockindex);
1873 }
1874
1876 active_chainstate.ActivateBestChain(state, /*pblock=*/nullptr,
1877 node.avalanche.get());
1878
1879 if (!state.IsValid()) {
1881 }
1882
1883 // Block to make sure wallet/indexers sync before returning
1884 CHECK_NONFATAL(node.validation_signals)
1885 ->SyncWithValidationInterfaceQueue();
1886
1887 return NullUniValue;
1888 },
1889 };
1890}
1891
1893 return RPCHelpMan{
1894 "getchaintxstats",
1895 "Compute statistics about the total number and rate of transactions "
1896 "in the chain.\n",
1897 {
1898 {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{"one month"},
1899 "Size of the window in number of blocks"},
1900 {"blockhash", RPCArg::Type::STR_HEX,
1901 RPCArg::DefaultHint{"chain tip"},
1902 "The hash of the block that ends the window."},
1903 },
1904 RPCResult{
1906 "",
1907 "",
1908 {
1910 "The timestamp for the final block in the window, "
1911 "expressed in " +
1913 {RPCResult::Type::NUM, "txcount", /*optional=*/true,
1914 "The total number of transactions in the chain up to "
1915 "that point, if known. It may be unknown when using "
1916 "assumeutxo."},
1917 {RPCResult::Type::STR_HEX, "window_final_block_hash",
1918 "The hash of the final block in the window"},
1919 {RPCResult::Type::NUM, "window_final_block_height",
1920 "The height of the final block in the window."},
1921 {RPCResult::Type::NUM, "window_block_count",
1922 "Size of the window in number of blocks"},
1923 {RPCResult::Type::NUM, "window_interval",
1924 "The elapsed time in the window in seconds. Only "
1925 "returned if \"window_block_count\" is > 0"},
1926 {RPCResult::Type::NUM, "window_tx_count", /*optional=*/true,
1927 "The number of transactions in the window. Only "
1928 "returned if \"window_block_count\" is > 0 and if "
1929 "txcount exists for the start and end of the window."},
1930 {RPCResult::Type::NUM, "txrate", /*optional=*/true,
1931 "The average rate of transactions per second in the "
1932 "window. Only returned if \"window_interval\" is > 0 "
1933 "and if window_tx_count exists."},
1934 }},
1935 RPCExamples{HelpExampleCli("getchaintxstats", "") +
1936 HelpExampleRpc("getchaintxstats", "2016")},
1937 [&](const RPCHelpMan &self, const Config &config,
1938 const JSONRPCRequest &request) -> UniValue {
1939 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1940 const CBlockIndex *pindex;
1941
1942 // By default: 1 month
1943 int blockcount =
1944 30 * 24 * 60 * 60 /
1945 config.GetChainParams().GetConsensus().nPowTargetSpacing;
1946
1947 if (request.params[1].isNull()) {
1948 LOCK(cs_main);
1949 pindex = chainman.ActiveTip();
1950 } else {
1951 BlockHash hash(ParseHashV(request.params[1], "blockhash"));
1952 LOCK(cs_main);
1953 pindex = chainman.m_blockman.LookupBlockIndex(hash);
1954 if (!pindex) {
1956 "Block not found");
1957 }
1958 if (!chainman.ActiveChain().Contains(pindex)) {
1960 "Block is not in main chain");
1961 }
1962 }
1963
1964 CHECK_NONFATAL(pindex != nullptr);
1965
1966 if (request.params[0].isNull()) {
1967 blockcount =
1968 std::max(0, std::min(blockcount, pindex->nHeight - 1));
1969 } else {
1970 blockcount = request.params[0].getInt<int>();
1971
1972 if (blockcount < 0 ||
1973 (blockcount > 0 && blockcount >= pindex->nHeight)) {
1975 "Invalid block count: "
1976 "should be between 0 and "
1977 "the block's height - 1");
1978 }
1979 }
1980
1981 const CBlockIndex &past_block{*CHECK_NONFATAL(
1982 pindex->GetAncestor(pindex->nHeight - blockcount))};
1983 const int64_t nTimeDiff{pindex->GetMedianTimePast() -
1984 past_block.GetMedianTimePast()};
1985
1987 ret.pushKV("time", pindex->GetBlockTime());
1988 if (pindex->m_chain_tx_count) {
1989 ret.pushKV("txcount", pindex->m_chain_tx_count);
1990 }
1991 ret.pushKV("window_final_block_hash",
1992 pindex->GetBlockHash().GetHex());
1993 ret.pushKV("window_final_block_height", pindex->nHeight);
1994 ret.pushKV("window_block_count", blockcount);
1995 if (blockcount > 0) {
1996 ret.pushKV("window_interval", nTimeDiff);
1997 if (pindex->m_chain_tx_count != 0 &&
1998 past_block.m_chain_tx_count != 0) {
1999 uint64_t window_tx_count =
2000 pindex->m_chain_tx_count - past_block.m_chain_tx_count;
2001 ret.pushKV("window_tx_count", window_tx_count);
2002 if (nTimeDiff > 0) {
2003 ret.pushKV("txrate",
2004 double(window_tx_count) / nTimeDiff);
2005 }
2006 }
2007 }
2008
2009 return ret;
2010 },
2011 };
2012}
2013
2014template <typename T>
2015static T CalculateTruncatedMedian(std::vector<T> &scores) {
2016 size_t size = scores.size();
2017 if (size == 0) {
2018 return T();
2019 }
2020
2021 std::sort(scores.begin(), scores.end());
2022 if (size % 2 == 0) {
2023 return (scores[size / 2 - 1] + scores[size / 2]) / 2;
2024 } else {
2025 return scores[size / 2];
2026 }
2027}
2028
2029template <typename T> static inline bool SetHasKeys(const std::set<T> &set) {
2030 return false;
2031}
2032template <typename T, typename Tk, typename... Args>
2033static inline bool SetHasKeys(const std::set<T> &set, const Tk &key,
2034 const Args &...args) {
2035 return (set.count(key) != 0) || SetHasKeys(set, args...);
2036}
2037
2038// outpoint (needed for the utxo index) + nHeight + fCoinBase
2039static constexpr size_t PER_UTXO_OVERHEAD =
2040 sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);
2041
2043 const auto ticker = Currency::getTicker();
2044 return RPCHelpMan{
2045 "getblockstats",
2046 "Compute per block statistics for a given window. All amounts are "
2047 "in " +
2048 ticker +
2049 ".\n"
2050 "It won't work for some heights with pruning.\n",
2051 {
2052 {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO,
2053 "The block hash or height of the target block",
2055 .type_str = {"", "string or numeric"}}},
2056 {"stats",
2058 RPCArg::DefaultHint{"all values"},
2059 "Values to plot (see result below)",
2060 {
2062 "Selected statistic"},
2064 "Selected statistic"},
2065 },
2067 },
2068 RPCResult{
2070 "",
2071 "",
2072 {
2073 {RPCResult::Type::NUM, "avgfee", "Average fee in the block"},
2074 {RPCResult::Type::NUM, "avgfeerate",
2075 "Average feerate (in satoshis per virtual byte)"},
2076 {RPCResult::Type::NUM, "avgtxsize", "Average transaction size"},
2077 {RPCResult::Type::STR_HEX, "blockhash",
2078 "The block hash (to check for potential reorgs)"},
2079 {RPCResult::Type::NUM, "height", "The height of the block"},
2080 {RPCResult::Type::NUM, "ins",
2081 "The number of inputs (excluding coinbase)"},
2082 {RPCResult::Type::NUM, "maxfee", "Maximum fee in the block"},
2083 {RPCResult::Type::NUM, "maxfeerate",
2084 "Maximum feerate (in satoshis per virtual byte)"},
2085 {RPCResult::Type::NUM, "maxtxsize", "Maximum transaction size"},
2086 {RPCResult::Type::NUM, "medianfee",
2087 "Truncated median fee in the block"},
2088 {RPCResult::Type::NUM, "medianfeerate",
2089 "Truncated median feerate (in " + ticker + " per byte)"},
2090 {RPCResult::Type::NUM, "mediantime",
2091 "The block median time past"},
2092 {RPCResult::Type::NUM, "mediantxsize",
2093 "Truncated median transaction size"},
2094 {RPCResult::Type::NUM, "minfee", "Minimum fee in the block"},
2095 {RPCResult::Type::NUM, "minfeerate",
2096 "Minimum feerate (in satoshis per virtual byte)"},
2097 {RPCResult::Type::NUM, "mintxsize", "Minimum transaction size"},
2098 {RPCResult::Type::NUM, "outs", "The number of outputs"},
2099 {RPCResult::Type::NUM, "subsidy", "The block subsidy"},
2100 {RPCResult::Type::NUM, "time", "The block time"},
2101 {RPCResult::Type::NUM, "total_out",
2102 "Total amount in all outputs (excluding coinbase and thus "
2103 "reward [ie subsidy + totalfee])"},
2104 {RPCResult::Type::NUM, "total_size",
2105 "Total size of all non-coinbase transactions"},
2106 {RPCResult::Type::NUM, "totalfee", "The fee total"},
2107 {RPCResult::Type::NUM, "txs",
2108 "The number of transactions (including coinbase)"},
2109 {RPCResult::Type::NUM, "utxo_increase",
2110 "The increase/decrease in the number of unspent outputs"},
2111 {RPCResult::Type::NUM, "utxo_size_inc",
2112 "The increase/decrease in size for the utxo index (not "
2113 "discounting op_return and similar)"},
2114 }},
2117 "getblockstats",
2118 R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
2119 HelpExampleCli("getblockstats",
2120 R"(1000 '["minfeerate","avgfeerate"]')") +
2122 "getblockstats",
2123 R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") +
2124 HelpExampleRpc("getblockstats",
2125 R"(1000, ["minfeerate","avgfeerate"])")},
2126 [&](const RPCHelpMan &self, const Config &config,
2127 const JSONRPCRequest &request) -> UniValue {
2128 ChainstateManager &chainman = EnsureAnyChainman(request.context);
2129 const CBlockIndex &pindex{*CHECK_NONFATAL(
2130 ParseHashOrHeight(request.params[0], chainman))};
2131
2132 std::set<std::string> stats;
2133 if (!request.params[1].isNull()) {
2134 const UniValue stats_univalue = request.params[1].get_array();
2135 for (unsigned int i = 0; i < stats_univalue.size(); i++) {
2136 const std::string stat = stats_univalue[i].get_str();
2137 stats.insert(stat);
2138 }
2139 }
2140
2141 const CBlock &block = GetBlockChecked(chainman.m_blockman, pindex);
2142 const CBlockUndo &blockUndo =
2143 GetUndoChecked(chainman.m_blockman, pindex);
2144
2145 // Calculate everything if nothing selected (default)
2146 const bool do_all = stats.size() == 0;
2147 const bool do_mediantxsize =
2148 do_all || stats.count("mediantxsize") != 0;
2149 const bool do_medianfee = do_all || stats.count("medianfee") != 0;
2150 const bool do_medianfeerate =
2151 do_all || stats.count("medianfeerate") != 0;
2152 const bool loop_inputs =
2153 do_all || do_medianfee || do_medianfeerate ||
2154 SetHasKeys(stats, "utxo_size_inc", "totalfee", "avgfee",
2155 "avgfeerate", "minfee", "maxfee", "minfeerate",
2156 "maxfeerate");
2157 const bool loop_outputs =
2158 do_all || loop_inputs || stats.count("total_out");
2159 const bool do_calculate_size =
2160 do_mediantxsize || loop_inputs ||
2161 SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize",
2162 "maxtxsize");
2163
2164 const int64_t blockMaxSize = config.GetMaxBlockSize();
2165 Amount maxfee = Amount::zero();
2166 Amount maxfeerate = Amount::zero();
2167 Amount minfee = MAX_MONEY;
2168 Amount minfeerate = MAX_MONEY;
2169 Amount total_out = Amount::zero();
2170 Amount totalfee = Amount::zero();
2171 int64_t inputs = 0;
2172 int64_t maxtxsize = 0;
2173 int64_t mintxsize = blockMaxSize;
2174 int64_t outputs = 0;
2175 int64_t total_size = 0;
2176 int64_t utxo_size_inc = 0;
2177 std::vector<Amount> fee_array;
2178 std::vector<Amount> feerate_array;
2179 std::vector<int64_t> txsize_array;
2180
2181 for (size_t i = 0; i < block.vtx.size(); ++i) {
2182 const auto &tx = block.vtx.at(i);
2183 outputs += tx->vout.size();
2184 Amount tx_total_out = Amount::zero();
2185 if (loop_outputs) {
2186 for (const CTxOut &out : tx->vout) {
2187 tx_total_out += out.nValue;
2188 utxo_size_inc +=
2190 }
2191 }
2192
2193 if (tx->IsCoinBase()) {
2194 continue;
2195 }
2196
2197 // Don't count coinbase's fake input
2198 inputs += tx->vin.size();
2199 // Don't count coinbase reward
2200 total_out += tx_total_out;
2201
2202 int64_t tx_size = 0;
2203 if (do_calculate_size) {
2204 tx_size = tx->GetTotalSize();
2205 if (do_mediantxsize) {
2206 txsize_array.push_back(tx_size);
2207 }
2208 maxtxsize = std::max(maxtxsize, tx_size);
2209 mintxsize = std::min(mintxsize, tx_size);
2210 total_size += tx_size;
2211 }
2212
2213 if (loop_inputs) {
2214 Amount tx_total_in = Amount::zero();
2215 const auto &txundo = blockUndo.vtxundo.at(i - 1);
2216 for (const Coin &coin : txundo.vprevout) {
2217 const CTxOut &prevoutput = coin.GetTxOut();
2218
2219 tx_total_in += prevoutput.nValue;
2220 utxo_size_inc -=
2221 GetSerializeSize(prevoutput) + PER_UTXO_OVERHEAD;
2222 }
2223
2224 Amount txfee = tx_total_in - tx_total_out;
2225 CHECK_NONFATAL(MoneyRange(txfee));
2226 if (do_medianfee) {
2227 fee_array.push_back(txfee);
2228 }
2229 maxfee = std::max(maxfee, txfee);
2230 minfee = std::min(minfee, txfee);
2231 totalfee += txfee;
2232
2233 Amount feerate = txfee / tx_size;
2234 if (do_medianfeerate) {
2235 feerate_array.push_back(feerate);
2236 }
2237 maxfeerate = std::max(maxfeerate, feerate);
2238 minfeerate = std::min(minfeerate, feerate);
2239 }
2240 }
2241
2242 UniValue ret_all(UniValue::VOBJ);
2243 ret_all.pushKV("avgfee",
2244 block.vtx.size() > 1
2245 ? (totalfee / int((block.vtx.size() - 1)))
2246 : Amount::zero());
2247 ret_all.pushKV("avgfeerate", total_size > 0
2248 ? (totalfee / total_size)
2249 : Amount::zero());
2250 ret_all.pushKV("avgtxsize",
2251 (block.vtx.size() > 1)
2252 ? total_size / (block.vtx.size() - 1)
2253 : 0);
2254 ret_all.pushKV("blockhash", pindex.GetBlockHash().GetHex());
2255 ret_all.pushKV("height", (int64_t)pindex.nHeight);
2256 ret_all.pushKV("ins", inputs);
2257 ret_all.pushKV("maxfee", maxfee);
2258 ret_all.pushKV("maxfeerate", maxfeerate);
2259 ret_all.pushKV("maxtxsize", maxtxsize);
2260 ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
2261 ret_all.pushKV("medianfeerate",
2262 CalculateTruncatedMedian(feerate_array));
2263 ret_all.pushKV("mediantime", pindex.GetMedianTimePast());
2264 ret_all.pushKV("mediantxsize",
2265 CalculateTruncatedMedian(txsize_array));
2266 ret_all.pushKV("minfee",
2267 minfee == MAX_MONEY ? Amount::zero() : minfee);
2268 ret_all.pushKV("minfeerate", minfeerate == MAX_MONEY
2269 ? Amount::zero()
2270 : minfeerate);
2271 ret_all.pushKV("mintxsize",
2272 mintxsize == blockMaxSize ? 0 : mintxsize);
2273 ret_all.pushKV("outs", outputs);
2274 ret_all.pushKV("subsidy", GetBlockSubsidy(pindex.nHeight,
2275 chainman.GetConsensus()));
2276 ret_all.pushKV("time", pindex.GetBlockTime());
2277 ret_all.pushKV("total_out", total_out);
2278 ret_all.pushKV("total_size", total_size);
2279 ret_all.pushKV("totalfee", totalfee);
2280 ret_all.pushKV("txs", (int64_t)block.vtx.size());
2281 ret_all.pushKV("utxo_increase", outputs - inputs);
2282 ret_all.pushKV("utxo_size_inc", utxo_size_inc);
2283
2284 if (do_all) {
2285 return ret_all;
2286 }
2287
2289 for (const std::string &stat : stats) {
2290 const UniValue &value = ret_all[stat];
2291 if (value.isNull()) {
2292 throw JSONRPCError(
2294 strprintf("Invalid selected statistic %s", stat));
2295 }
2296 ret.pushKV(stat, value);
2297 }
2298 return ret;
2299 },
2300 };
2301}
2302
2303namespace {
2305static bool FindScriptPubKey(std::atomic<int> &scan_progress,
2306 const std::atomic<bool> &should_abort,
2307 int64_t &count, CCoinsViewCursor *cursor,
2308 const std::set<CScript> &needles,
2309 std::map<COutPoint, Coin> &out_results,
2310 std::function<void()> &interruption_point) {
2311 scan_progress = 0;
2312 count = 0;
2313 while (cursor->Valid()) {
2314 COutPoint key;
2315 Coin coin;
2316 if (!cursor->GetKey(key) || !cursor->GetValue(coin)) {
2317 return false;
2318 }
2319 if (++count % 8192 == 0) {
2320 interruption_point();
2321 if (should_abort) {
2322 // allow to abort the scan via the abort reference
2323 return false;
2324 }
2325 }
2326 if (count % 256 == 0) {
2327 // update progress reference every 256 item
2328 const TxId &txid = key.GetTxId();
2329 uint32_t high = 0x100 * *txid.begin() + *(txid.begin() + 1);
2330 scan_progress = int(high * 100.0 / 65536.0 + 0.5);
2331 }
2332 if (needles.count(coin.GetTxOut().scriptPubKey)) {
2333 out_results.emplace(key, coin);
2334 }
2335 cursor->Next();
2336 }
2337 scan_progress = 100;
2338 return true;
2339}
2340} // namespace
2341
2343static std::atomic<int> g_scan_progress;
2344static std::atomic<bool> g_scan_in_progress;
2345static std::atomic<bool> g_should_abort_scan;
2347private:
2348 bool m_could_reserve{false};
2349
2350public:
2351 explicit CoinsViewScanReserver() = default;
2352
2353 bool reserve() {
2355 if (g_scan_in_progress.exchange(true)) {
2356 return false;
2357 }
2358 m_could_reserve = true;
2359 return true;
2360 }
2361
2363 if (m_could_reserve) {
2364 g_scan_in_progress = false;
2365 }
2366 }
2367};
2368
2370 const auto ticker = Currency::getTicker();
2371 return RPCHelpMan{
2372 "scantxoutset",
2373 "Scans the unspent transaction output set for entries that match "
2374 "certain output descriptors.\n"
2375 "Examples of output descriptors are:\n"
2376 " addr(<address>) Outputs whose scriptPubKey "
2377 "corresponds to the specified address (does not include P2PK)\n"
2378 " raw(<hex script>) Outputs whose scriptPubKey "
2379 "equals the specified hex scripts\n"
2380 " combo(<pubkey>) P2PK and P2PKH outputs for "
2381 "the given pubkey\n"
2382 " pkh(<pubkey>) P2PKH outputs for the given "
2383 "pubkey\n"
2384 " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for "
2385 "the given threshold and pubkeys\n"
2386 "\nIn the above, <pubkey> either refers to a fixed public key in "
2387 "hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
2388 "or more path elements separated by \"/\", and optionally ending in "
2389 "\"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
2390 "unhardened or hardened child keys.\n"
2391 "In the latter case, a range needs to be specified by below if "
2392 "different from 1000.\n"
2393 "For more information on output descriptors, see the documentation in "
2394 "the doc/descriptors.md file.\n",
2395 {
2397 "The action to execute\n"
2398 " \"start\" for starting a "
2399 "scan\n"
2400 " \"abort\" for aborting the "
2401 "current scan (returns true when abort was successful)\n"
2402 " \"status\" for "
2403 "progress report (in %) of the current scan"},
2404 {"scanobjects",
2407 "Array of scan objects. Required for \"start\" action\n"
2408 " Every scan object is either a "
2409 "string descriptor or an object:",
2410 {
2412 "An output descriptor"},
2413 {
2414 "",
2417 "An object with output descriptor and metadata",
2418 {
2420 "An output descriptor"},
2421 {"range", RPCArg::Type::RANGE, RPCArg::Default{1000},
2422 "The range of HD chain indexes to explore (either "
2423 "end or [begin,end])"},
2424 },
2425 },
2426 },
2427 RPCArgOptions{.oneline_description = "[scanobjects,...]"}},
2428 },
2429 {
2430 RPCResult{"When action=='abort'", RPCResult::Type::BOOL, "", ""},
2431 RPCResult{"When action=='status' and no scan is in progress",
2432 RPCResult::Type::NONE, "", ""},
2433 RPCResult{
2434 "When action=='status' and scan is in progress",
2436 "",
2437 "",
2438 {
2439 {RPCResult::Type::NUM, "progress", "The scan progress"},
2440 }},
2441 RPCResult{
2442 "When action=='start'",
2444 "",
2445 "",
2446 {
2447 {RPCResult::Type::BOOL, "success",
2448 "Whether the scan was completed"},
2449 {RPCResult::Type::NUM, "txouts",
2450 "The number of unspent transaction outputs scanned"},
2451 {RPCResult::Type::NUM, "height",
2452 "The current block height (index)"},
2453 {RPCResult::Type::STR_HEX, "bestblock",
2454 "The hash of the block at the tip of the chain"},
2456 "unspents",
2457 "",
2458 {
2460 "",
2461 "",
2462 {
2463 {RPCResult::Type::STR_HEX, "txid",
2464 "The transaction id"},
2465 {RPCResult::Type::NUM, "vout", "The vout value"},
2466 {RPCResult::Type::STR_HEX, "scriptPubKey",
2467 "The script key"},
2468 {RPCResult::Type::STR, "desc",
2469 "A specialized descriptor for the matched "
2470 "scriptPubKey"},
2471 {RPCResult::Type::STR_AMOUNT, "amount",
2472 "The total amount in " + ticker +
2473 " of the unspent output"},
2474 {RPCResult::Type::BOOL, "coinbase",
2475 "Whether this is a coinbase output"},
2476 {RPCResult::Type::NUM, "height",
2477 "Height of the unspent transaction output"},
2478 }},
2479 }},
2480 {RPCResult::Type::STR_AMOUNT, "total_amount",
2481 "The total amount of all found unspent outputs in " +
2482 ticker},
2483 }},
2484 },
2485 RPCExamples{""},
2486 [&](const RPCHelpMan &self, const Config &config,
2487 const JSONRPCRequest &request) -> UniValue {
2488 UniValue result(UniValue::VOBJ);
2489 const auto action{self.Arg<std::string>("action")};
2490 if (action == "status") {
2491 CoinsViewScanReserver reserver;
2492 if (reserver.reserve()) {
2493 // no scan in progress
2494 return NullUniValue;
2495 }
2496 result.pushKV("progress", g_scan_progress.load());
2497 return result;
2498 } else if (action == "abort") {
2499 CoinsViewScanReserver reserver;
2500 if (reserver.reserve()) {
2501 // reserve was possible which means no scan was running
2502 return false;
2503 }
2504 // set the abort flag
2505 g_should_abort_scan = true;
2506 return true;
2507 } else if (action == "start") {
2508 CoinsViewScanReserver reserver;
2509 if (!reserver.reserve()) {
2511 "Scan already in progress, use action "
2512 "\"abort\" or \"status\"");
2513 }
2514
2515 if (request.params.size() < 2) {
2517 "scanobjects argument is required for "
2518 "the start action");
2519 }
2520
2521 std::set<CScript> needles;
2522 std::map<CScript, std::string> descriptors;
2523 Amount total_in = Amount::zero();
2524
2525 // loop through the scan objects
2526 for (const UniValue &scanobject :
2527 request.params[1].get_array().getValues()) {
2528 FlatSigningProvider provider;
2529 auto scripts =
2530 EvalDescriptorStringOrObject(scanobject, provider);
2531 for (CScript &script : scripts) {
2532 std::string inferred =
2533 InferDescriptor(script, provider)->ToString();
2534 needles.emplace(script);
2535 descriptors.emplace(std::move(script),
2536 std::move(inferred));
2537 }
2538 }
2539
2540 // Scan the unspent transaction output set for inputs
2541 UniValue unspents(UniValue::VARR);
2542 std::vector<CTxOut> input_txos;
2543 std::map<COutPoint, Coin> coins;
2544 g_should_abort_scan = false;
2545 g_scan_progress = 0;
2546 int64_t count = 0;
2547 std::unique_ptr<CCoinsViewCursor> pcursor;
2548 const CBlockIndex *tip;
2549 NodeContext &node = EnsureAnyNodeContext(request.context);
2550 {
2552 LOCK(cs_main);
2553 Chainstate &active_chainstate = chainman.ActiveChainstate();
2554 active_chainstate.ForceFlushStateToDisk();
2555 pcursor = CHECK_NONFATAL(std::unique_ptr<CCoinsViewCursor>(
2556 active_chainstate.CoinsDB().Cursor()));
2557 tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
2558 }
2559 bool res = FindScriptPubKey(
2560 g_scan_progress, g_should_abort_scan, count, pcursor.get(),
2561 needles, coins, node.rpc_interruption_point);
2562 result.pushKV("success", res);
2563 result.pushKV("txouts", count);
2564 result.pushKV("height", tip->nHeight);
2565 result.pushKV("bestblock", tip->GetBlockHash().GetHex());
2566
2567 for (const auto &it : coins) {
2568 const COutPoint &outpoint = it.first;
2569 const Coin &coin = it.second;
2570 const CTxOut &txo = coin.GetTxOut();
2571 input_txos.push_back(txo);
2572 total_in += txo.nValue;
2573
2574 UniValue unspent(UniValue::VOBJ);
2575 unspent.pushKV("txid", outpoint.GetTxId().GetHex());
2576 unspent.pushKV("vout", int32_t(outpoint.GetN()));
2577 unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
2578 unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
2579 unspent.pushKV("amount", txo.nValue);
2580 unspent.pushKV("coinbase", coin.IsCoinBase());
2581 unspent.pushKV("height", int32_t(coin.GetHeight()));
2582
2583 unspents.push_back(std::move(unspent));
2584 }
2585 result.pushKV("unspents", std::move(unspents));
2586 result.pushKV("total_amount", total_in);
2587 } else {
2589 strprintf("Invalid action '%s'", action));
2590 }
2591 return result;
2592 },
2593 };
2594}
2595
2597 return RPCHelpMan{
2598 "getblockfilter",
2599 "Retrieve a BIP 157 content filter for a particular block.\n",
2600 {
2602 "The hash of the block"},
2603 {"filtertype", RPCArg::Type::STR, RPCArg::Default{"basic"},
2604 "The type name of the filter"},
2605 },
2607 "",
2608 "",
2609 {
2610 {RPCResult::Type::STR_HEX, "filter",
2611 "the hex-encoded filter data"},
2612 {RPCResult::Type::STR_HEX, "header",
2613 "the hex-encoded filter header"},
2614 }},
2616 HelpExampleCli("getblockfilter",
2617 "\"00000000c937983704a73af28acdec37b049d214a"
2618 "dbda81d7e2a3dd146f6ed09\" \"basic\"") +
2619 HelpExampleRpc("getblockfilter",
2620 "\"00000000c937983704a73af28acdec37b049d214adbda81d7"
2621 "e2a3dd146f6ed09\", \"basic\"")},
2622 [&](const RPCHelpMan &self, const Config &config,
2623 const JSONRPCRequest &request) -> UniValue {
2624 const BlockHash block_hash(
2625 ParseHashV(request.params[0], "blockhash"));
2626 std::string filtertype_name = "basic";
2627 if (!request.params[1].isNull()) {
2628 filtertype_name = request.params[1].get_str();
2629 }
2630
2631 BlockFilterType filtertype;
2632 if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2634 "Unknown filtertype");
2635 }
2636
2637 BlockFilterIndex *index = GetBlockFilterIndex(filtertype);
2638 if (!index) {
2640 "Index is not enabled for filtertype " +
2641 filtertype_name);
2642 }
2643
2644 const CBlockIndex *block_index;
2645 bool block_was_connected;
2646 {
2647 ChainstateManager &chainman =
2648 EnsureAnyChainman(request.context);
2649 LOCK(cs_main);
2650 block_index = chainman.m_blockman.LookupBlockIndex(block_hash);
2651 if (!block_index) {
2653 "Block not found");
2654 }
2655 block_was_connected =
2656 block_index->IsValid(BlockValidity::SCRIPTS);
2657 }
2658
2659 bool index_ready = index->BlockUntilSyncedToCurrentChain();
2660
2661 BlockFilter filter;
2662 uint256 filter_header;
2663 if (!index->LookupFilter(block_index, filter) ||
2664 !index->LookupFilterHeader(block_index, filter_header)) {
2665 int err_code;
2666 std::string errmsg = "Filter not found.";
2667
2668 if (!block_was_connected) {
2669 err_code = RPC_INVALID_ADDRESS_OR_KEY;
2670 errmsg += " Block was not connected to active chain.";
2671 } else if (!index_ready) {
2672 err_code = RPC_MISC_ERROR;
2673 errmsg += " Block filters are still in the process of "
2674 "being indexed.";
2675 } else {
2676 err_code = RPC_INTERNAL_ERROR;
2677 errmsg += " This error is unexpected and indicates index "
2678 "corruption.";
2679 }
2680
2681 throw JSONRPCError(err_code, errmsg);
2682 }
2683
2685 ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
2686 ret.pushKV("header", filter_header.GetHex());
2687 return ret;
2688 },
2689 };
2690}
2691
2698
2699public:
2700 NetworkDisable(CConnman &connman) : m_connman(connman) {
2704 "Network activity could not be suspended.");
2705 }
2706 };
2708};
2709
2718
2719public:
2722 const CBlockIndex &index)
2723 : m_chainman(chainman), m_avalanche(avalanche),
2724 m_invalidate_index(index) {
2727 };
2731 };
2732};
2733
2740 return RPCHelpMan{
2741 "dumptxoutset",
2742 "Write the serialized UTXO set to a file. This can be used in "
2743 "loadtxoutset afterwards if this snapshot height is supported in the "
2744 "chainparams as well.\n\n"
2745 "Unless the the \"latest\" type is requested, the node will roll back "
2746 "to the requested height and network activity will be suspended during "
2747 "this process. "
2748 "Because of this it is discouraged to interact with the node in any "
2749 "other way during the execution of this call to avoid inconsistent "
2750 "results and race conditions, particularly RPCs that interact with "
2751 "blockstorage.\n\n"
2752 "This call may take several minutes. Make sure to use no RPC timeout "
2753 "(bitcoin-cli -rpcclienttimeout=0)",
2754
2755 {
2757 "path to the output file. If relative, will be prefixed by "
2758 "datadir."},
2759 {"type", RPCArg::Type::STR, RPCArg::Default(""),
2760 "The type of snapshot to create. Can be \"latest\" to create a "
2761 "snapshot of the current UTXO set or \"rollback\" to temporarily "
2762 "roll back the state of the node to a historical block before "
2763 "creating the snapshot of a historical UTXO set. This parameter "
2764 "can be omitted if a separate \"rollback\" named parameter is "
2765 "specified indicating the height or hash of a specific historical "
2766 "block. If \"rollback\" is specified and separate \"rollback\" "
2767 "named parameter is not specified, this will roll back to the "
2768 "latest valid snapshot block that can currently be loaded with "
2769 "loadtxoutset."},
2770 {
2771 "options",
2774 "",
2775 {
2777 "Height or hash of the block to roll back to before "
2778 "creating the snapshot. Note: The further this number is "
2779 "from the tip, the longer this process will take. "
2780 "Consider setting a higher -rpcclienttimeout value in "
2781 "this case.",
2783 .type_str = {"", "string or numeric"}}},
2784 },
2785 },
2786 },
2788 "",
2789 "",
2790 {
2791 {RPCResult::Type::NUM, "coins_written",
2792 "the number of coins written in the snapshot"},
2793 {RPCResult::Type::STR_HEX, "base_hash",
2794 "the hash of the base of the snapshot"},
2795 {RPCResult::Type::NUM, "base_height",
2796 "the height of the base of the snapshot"},
2797 {RPCResult::Type::STR, "path",
2798 "the absolute path that the snapshot was written to"},
2799 {RPCResult::Type::STR_HEX, "txoutset_hash",
2800 "the hash of the UTXO set contents"},
2801 {RPCResult::Type::NUM, "nchaintx",
2802 "the number of transactions in the chain up to and "
2803 "including the base block"},
2804 }},
2805 RPCExamples{HelpExampleCli("-rpcclienttimeout=0 dumptxoutset",
2806 "utxo.dat latest") +
2807 HelpExampleCli("-rpcclienttimeout=0 dumptxoutset",
2808 "utxo.dat rollback") +
2809 HelpExampleCli("-rpcclienttimeout=0 -named dumptxoutset",
2810 R"(utxo.dat rollback=853456)")},
2811 [&](const RPCHelpMan &self, const Config &config,
2812 const JSONRPCRequest &request) -> UniValue {
2813 NodeContext &node = EnsureAnyNodeContext(request.context);
2814 const CBlockIndex *tip{WITH_LOCK(
2815 ::cs_main, return node.chainman->ActiveChain().Tip())};
2816 const CBlockIndex *target_index{nullptr};
2817 const std::string snapshot_type{self.Arg<std::string>("type")};
2818 const UniValue options{request.params[2].isNull()
2820 : request.params[2]};
2821 if (options.exists("rollback")) {
2822 if (!snapshot_type.empty() && snapshot_type != "rollback") {
2823 throw JSONRPCError(
2825 strprintf("Invalid snapshot type \"%s\" specified with "
2826 "rollback option",
2827 snapshot_type));
2828 }
2829 target_index =
2830 ParseHashOrHeight(options["rollback"], *node.chainman);
2831 } else if (snapshot_type == "rollback") {
2832 auto snapshot_heights =
2833 node.chainman->GetParams().GetAvailableSnapshotHeights();
2834 CHECK_NONFATAL(snapshot_heights.size() > 0);
2835 auto max_height = std::max_element(snapshot_heights.begin(),
2836 snapshot_heights.end());
2837 target_index = ParseHashOrHeight(*max_height, *node.chainman);
2838 } else if (snapshot_type == "latest") {
2839 target_index = tip;
2840 } else {
2841 throw JSONRPCError(
2843 strprintf("Invalid snapshot type \"%s\" specified. Please "
2844 "specify \"rollback\" or \"latest\"",
2845 snapshot_type));
2846 }
2847
2848 const ArgsManager &args{EnsureAnyArgsman(request.context)};
2849 const fs::path path = fsbridge::AbsPathJoin(
2850 args.GetDataDirNet(), fs::u8path(request.params[0].get_str()));
2851 // Write to a temporary path and then move into `path` on completion
2852 // to avoid confusion due to an interruption.
2853 const fs::path temppath = fsbridge::AbsPathJoin(
2854 args.GetDataDirNet(),
2855 fs::u8path(request.params[0].get_str() + ".incomplete"));
2856
2857 if (fs::exists(path)) {
2859 path.u8string() +
2860 " already exists. If you are sure this "
2861 "is what you want, "
2862 "move it out of the way first");
2863 }
2864
2865 FILE *file{fsbridge::fopen(temppath, "wb")};
2866 AutoFile afile{file};
2867
2868 CConnman &connman = EnsureConnman(node);
2869 const CBlockIndex *invalidate_index{nullptr};
2870 std::optional<NetworkDisable> disable_network;
2871 std::optional<TemporaryRollback> temporary_rollback;
2872
2873 // If the user wants to dump the txoutset of the current tip, we
2874 // don't have to roll back at all
2875 if (target_index != tip) {
2876 // If the node is running in pruned mode we ensure all necessary
2877 // block data is available before starting to roll back.
2878 if (node.chainman->m_blockman.IsPruneMode()) {
2879 LOCK(node.chainman->GetMutex());
2880 const CBlockIndex *current_tip{
2881 node.chainman->ActiveChain().Tip()};
2882 const CBlockIndex *first_block{
2883 node.chainman->m_blockman.GetFirstBlock(
2884 *current_tip,
2885 /*status_test=*/[](const BlockStatus &status) {
2886 return status.hasData() && status.hasUndo();
2887 })};
2888 if (first_block->nHeight > target_index->nHeight) {
2889 throw JSONRPCError(
2891 "Could not roll back to requested height since "
2892 "necessary block data is already pruned.");
2893 }
2894 }
2895
2896 // Suspend network activity for the duration of the process when
2897 // we are rolling back the chain to get a utxo set from a past
2898 // height. We do this so we don't punish peers that send us that
2899 // send us data that seems wrong in this temporary state. For
2900 // example a normal new block would be classified as a block
2901 // connecting an invalid block.
2902 // Skip if the network is already disabled because this
2903 // automatically re-enables the network activity at the end of
2904 // the process which may not be what the user wants.
2905 if (connman.GetNetworkActive()) {
2906 disable_network.emplace(connman);
2907 }
2908
2909 invalidate_index = WITH_LOCK(
2910 ::cs_main,
2911 return node.chainman->ActiveChain().Next(target_index));
2912 temporary_rollback.emplace(*node.chainman, node.avalanche.get(),
2913 *invalidate_index);
2914 }
2915
2916 Chainstate *chainstate;
2917 std::unique_ptr<CCoinsViewCursor> cursor;
2918 CCoinsStats stats;
2919 {
2920 // Lock the chainstate before calling PrepareUtxoSnapshot, to
2921 // be able to get a UTXO database cursor while the chain is
2922 // pointing at the target block. After that, release the lock
2923 // while calling WriteUTXOSnapshot. The cursor will remain
2924 // valid and be used by WriteUTXOSnapshot to write a consistent
2925 // snapshot even if the chainstate changes.
2926 LOCK(node.chainman->GetMutex());
2927 chainstate = &node.chainman->ActiveChainstate();
2928
2929 // In case there is any issue with a block being read from disk
2930 // we need to stop here, otherwise the dump could still be
2931 // created for the wrong height. The new tip could also not be
2932 // the target block if we have a stale sister block of
2933 // invalidate_index. This block (or a descendant) would be
2934 // activated as the new tip and we would not get to
2935 // new_tip_index.
2936 if (target_index != chainstate->m_chain.Tip()) {
2938 "Failed to roll back to requested height, "
2939 "reverting to tip.\n");
2940 throw JSONRPCError(
2942 "Could not roll back to requested height.");
2943 } else {
2944 std::tie(cursor, stats, tip) = PrepareUTXOSnapshot(
2945 *chainstate, node.rpc_interruption_point);
2946 }
2947 }
2948
2949 UniValue result =
2950 WriteUTXOSnapshot(*chainstate, cursor.get(), &stats, tip, afile,
2951 path, temppath, node.rpc_interruption_point);
2952 fs::rename(temppath, path);
2953
2954 return result;
2955 },
2956 };
2957}
2958
2959std::tuple<std::unique_ptr<CCoinsViewCursor>, CCoinsStats, const CBlockIndex *>
2961 const std::function<void()> &interruption_point) {
2962 std::unique_ptr<CCoinsViewCursor> pcursor;
2963 std::optional<CCoinsStats> maybe_stats;
2964 const CBlockIndex *tip;
2965
2966 {
2967 // We need to lock cs_main to ensure that the coinsdb isn't
2968 // written to between (i) flushing coins cache to disk
2969 // (coinsdb), (ii) getting stats based upon the coinsdb, and
2970 // (iii) constructing a cursor to the coinsdb for use in
2971 // WriteUTXOSnapshot.
2972 //
2973 // Cursors returned by leveldb iterate over snapshots, so the
2974 // contents of the pcursor will not be affected by simultaneous
2975 // writes during use below this block.
2976 //
2977 // See discussion here:
2978 // https://github.com/bitcoin/bitcoin/pull/15606#discussion_r274479369
2979 //
2981
2982 chainstate.ForceFlushStateToDisk();
2983
2984 maybe_stats = GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman,
2985 CoinStatsHashType::HASH_SERIALIZED,
2986 interruption_point);
2987 if (!maybe_stats) {
2988 throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
2989 }
2990
2991 pcursor =
2992 std::unique_ptr<CCoinsViewCursor>(chainstate.CoinsDB().Cursor());
2993 tip = CHECK_NONFATAL(
2994 chainstate.m_blockman.LookupBlockIndex(maybe_stats->hashBlock));
2995 }
2996
2997 return {std::move(pcursor), *CHECK_NONFATAL(maybe_stats), tip};
2998}
2999
3001 CCoinsStats *maybe_stats, const CBlockIndex *tip,
3002 AutoFile &afile, const fs::path &path,
3003 const fs::path &temppath,
3004 const std::function<void()> &interruption_point) {
3006 strprintf("writing UTXO snapshot at height %s (%s) to file %s (via %s)",
3007 tip->nHeight, tip->GetBlockHash().ToString(),
3008 fs::PathToString(path), fs::PathToString(temppath)));
3009
3010 SnapshotMetadata metadata{chainstate.m_chainman.GetParams().DiskMagic(),
3011 tip->GetBlockHash(), maybe_stats->coins_count};
3012
3013 afile << metadata;
3014
3015 COutPoint key;
3016 TxId last_txid;
3017 Coin coin;
3018 unsigned int iter{0};
3019 size_t written_coins_count{0};
3020 std::vector<std::pair<uint32_t, Coin>> coins;
3021
3022 // To reduce space the serialization format of the snapshot avoids
3023 // duplication of tx hashes. The code takes advantage of the guarantee by
3024 // leveldb that keys are lexicographically sorted.
3025 // In the coins vector we collect all coins that belong to a certain tx hash
3026 // (key.hash) and when we have them all (key.hash != last_hash) we write
3027 // them to file using the below lambda function.
3028 // See also https://github.com/bitcoin/bitcoin/issues/25675
3029 auto write_coins_to_file =
3030 [&](AutoFile &afile, const TxId &last_txid,
3031 const std::vector<std::pair<uint32_t, Coin>> &coins,
3032 size_t &written_coins_count) {
3033 afile << last_txid;
3034 WriteCompactSize(afile, coins.size());
3035 for (const auto &[n, coin_] : coins) {
3036 WriteCompactSize(afile, n);
3037 afile << coin_;
3038 ++written_coins_count;
3039 }
3040 };
3041
3042 pcursor->GetKey(key);
3043 last_txid = key.GetTxId();
3044 while (pcursor->Valid()) {
3045 if (iter % 5000 == 0) {
3046 interruption_point();
3047 }
3048 ++iter;
3049 if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
3050 if (key.GetTxId() != last_txid) {
3051 write_coins_to_file(afile, last_txid, coins,
3052 written_coins_count);
3053 last_txid = key.GetTxId();
3054 coins.clear();
3055 }
3056 coins.emplace_back(key.GetN(), coin);
3057 }
3058 pcursor->Next();
3059 }
3060
3061 if (!coins.empty()) {
3062 write_coins_to_file(afile, last_txid, coins, written_coins_count);
3063 }
3064
3065 CHECK_NONFATAL(written_coins_count == maybe_stats->coins_count);
3066
3067 afile.fclose();
3068
3069 UniValue result(UniValue::VOBJ);
3070 result.pushKV("coins_written", written_coins_count);
3071 result.pushKV("base_hash", tip->GetBlockHash().ToString());
3072 result.pushKV("base_height", tip->nHeight);
3073 result.pushKV("path", path.u8string());
3074 result.pushKV("txoutset_hash", maybe_stats->hashSerialized.ToString());
3075 result.pushKV("nchaintx", tip->m_chain_tx_count);
3076 return result;
3077}
3078
3080 AutoFile &afile, const fs::path &path,
3081 const fs::path &tmppath) {
3082 auto [cursor, stats, tip]{WITH_LOCK(
3083 ::cs_main,
3084 return PrepareUTXOSnapshot(chainstate, node.rpc_interruption_point))};
3085 return WriteUTXOSnapshot(chainstate, cursor.get(), &stats, tip, afile, path,
3086 tmppath, node.rpc_interruption_point);
3087}
3088
3090 return RPCHelpMan{
3091 "loadtxoutset",
3092 "Load the serialized UTXO set from a file.\n"
3093 "Once this snapshot is loaded, its contents will be deserialized into "
3094 "a second chainstate data structure, which is then used to sync to the "
3095 "network's tip. "
3096 "Meanwhile, the original chainstate will complete the initial block "
3097 "download process in the background, eventually validating up to the "
3098 "block that the snapshot is based upon.\n\n"
3099 "The result is a usable bitcoind instance that is current with the "
3100 "network tip in a matter of minutes rather than hours. UTXO snapshot "
3101 "are typically obtained from third-party sources (HTTP, torrent, etc.) "
3102 "which is reasonable since their contents are always checked by "
3103 "hash.\n\n"
3104 "This RPC is incompatible with the -chronik init option, and a node "
3105 "with multiple chainstates may not be restarted with -chronik. After "
3106 "the background validation is finished and the chainstates are merged, "
3107 "the node can be restarted again with Chronik.\n\n"
3108 "You can find more information on this process in the `assumeutxo` "
3109 "design document (https://www.bitcoinabc.org/doc/assumeutxo.html).",
3110 {
3112 "path to the snapshot file. If relative, will be prefixed by "
3113 "datadir."},
3114 },
3116 "",
3117 "",
3118 {
3119 {RPCResult::Type::NUM, "coins_loaded",
3120 "the number of coins loaded from the snapshot"},
3121 {RPCResult::Type::STR_HEX, "tip_hash",
3122 "the hash of the base of the snapshot"},
3123 {RPCResult::Type::NUM, "base_height",
3124 "the height of the base of the snapshot"},
3125 {RPCResult::Type::STR, "path",
3126 "the absolute path that the snapshot was loaded from"},
3127 }},
3129 HelpExampleCli("loadtxoutset -rpcclienttimeout=0", "utxo.dat")},
3130 [&](const RPCHelpMan &self, const Config &config,
3131 const JSONRPCRequest &request) -> UniValue {
3132 NodeContext &node = EnsureAnyNodeContext(request.context);
3135 const fs::path path{AbsPathForConfigVal(
3136 args, fs::u8path(self.Arg<std::string>("path")))};
3137
3138 if (args.GetBoolArg("-chronik", false)) {
3139 throw JSONRPCError(
3141 "loadtxoutset is not compatible with Chronik.");
3142 }
3143
3144 FILE *file{fsbridge::fopen(path, "rb")};
3145 AutoFile afile{file};
3146 if (afile.IsNull()) {
3148 "Couldn't open file " + path.u8string() +
3149 " for reading.");
3150 }
3151
3152 SnapshotMetadata metadata{chainman.GetParams().DiskMagic()};
3153 try {
3154 afile >> metadata;
3155 } catch (const std::ios_base::failure &e) {
3156 throw JSONRPCError(
3158 strprintf("Unable to parse metadata: %s", e.what()));
3159 }
3160
3161 auto activation_result{
3162 chainman.ActivateSnapshot(afile, metadata, false)};
3163 if (!activation_result) {
3164 throw JSONRPCError(
3166 strprintf("Unable to load UTXO snapshot: %s. (%s)",
3167 util::ErrorString(activation_result).original,
3168 path.u8string()));
3169 }
3170
3171 CBlockIndex &snapshot_index{*CHECK_NONFATAL(*activation_result)};
3172
3173 // Because we can't provide historical blocks during tip or
3174 // background sync. Update local services to reflect we are a
3175 // limited peer until we are fully sync.
3176 node.connman->RemoveLocalServices(NODE_NETWORK);
3177 // Setting the limited state is usually redundant because the node
3178 // can always provide the last 288 blocks, but it doesn't hurt to
3179 // set it.
3180 node.connman->AddLocalServices(NODE_NETWORK_LIMITED);
3181
3182 UniValue result(UniValue::VOBJ);
3183 result.pushKV("coins_loaded", metadata.m_coins_count);
3184 result.pushKV("tip_hash", snapshot_index.GetBlockHash().ToString());
3185 result.pushKV("base_height", snapshot_index.nHeight);
3186 result.pushKV("path", fs::PathToString(path));
3187 return result;
3188 },
3189 };
3190}
3191
3192const std::vector<RPCResult> RPCHelpForChainstate{
3193 {RPCResult::Type::NUM, "blocks", "number of blocks in this chainstate"},
3194 {RPCResult::Type::STR_HEX, "bestblockhash", "blockhash of the tip"},
3195 {RPCResult::Type::NUM, "difficulty", "difficulty of the tip"},
3196 {RPCResult::Type::NUM, "verificationprogress",
3197 "progress towards the network tip"},
3198 {RPCResult::Type::STR_HEX, "snapshot_blockhash", /*optional=*/true,
3199 "the base block of the snapshot this chainstate is based on, if any"},
3200 {RPCResult::Type::NUM, "coins_db_cache_bytes", "size of the coinsdb cache"},
3201 {RPCResult::Type::NUM, "coins_tip_cache_bytes",
3202 "size of the coinstip cache"},
3203 {RPCResult::Type::BOOL, "validated",
3204 "whether the chainstate is fully validated. True if all blocks in the "
3205 "chainstate were validated, false if the chain is based on a snapshot and "
3206 "the snapshot has not yet been validated."},
3207
3208};
3209
3211 return RPCHelpMan{
3212 "getchainstates",
3213 "\nReturn information about chainstates.\n",
3214 {},
3216 "",
3217 "",
3218 {
3219 {RPCResult::Type::NUM, "headers",
3220 "the number of headers seen so far"},
3222 "chainstates",
3223 "list of the chainstates ordered by work, with the "
3224 "most-work (active) chainstate last",
3225 {
3227 }},
3228 }},
3229 RPCExamples{HelpExampleCli("getchainstates", "") +
3230 HelpExampleRpc("getchainstates", "")},
3231 [&](const RPCHelpMan &self, const Config &config,
3232 const JSONRPCRequest &request) -> UniValue {
3233 LOCK(cs_main);
3235
3236 ChainstateManager &chainman = EnsureAnyChainman(request.context);
3237
3238 auto make_chain_data =
3239 [&](const Chainstate &chainstate,
3240 bool validated) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
3243 if (!chainstate.m_chain.Tip()) {
3244 return data;
3245 }
3246 const CChain &chain = chainstate.m_chain;
3247 const CBlockIndex *tip = chain.Tip();
3248
3249 data.pushKV("blocks", chain.Height());
3250 data.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
3251 data.pushKV("difficulty", GetDifficulty(*tip));
3252 data.pushKV(
3253 "verificationprogress",
3254 GuessVerificationProgress(Params().TxData(), tip));
3255 data.pushKV("coins_db_cache_bytes",
3256 chainstate.m_coinsdb_cache_size_bytes);
3257 data.pushKV("coins_tip_cache_bytes",
3258 chainstate.m_coinstip_cache_size_bytes);
3259 if (chainstate.m_from_snapshot_blockhash) {
3260 data.pushKV(
3261 "snapshot_blockhash",
3262 chainstate.m_from_snapshot_blockhash->ToString());
3263 }
3264 data.pushKV("validated", validated);
3265 return data;
3266 };
3267
3268 obj.pushKV("headers", chainman.m_best_header
3269 ? chainman.m_best_header->nHeight
3270 : -1);
3271
3272 const auto &chainstates = chainman.GetAll();
3273 UniValue obj_chainstates{UniValue::VARR};
3274 for (Chainstate *cs : chainstates) {
3275 obj_chainstates.push_back(
3276 make_chain_data(*cs, !cs->m_from_snapshot_blockhash ||
3277 chainstates.size() == 1));
3278 }
3279 obj.pushKV("chainstates", std::move(obj_chainstates));
3280 return obj;
3281 }};
3282}
3283
3285 // clang-format off
3286 static const CRPCCommand commands[] = {
3287 // category actor (function)
3288 // ------------------ ----------------------
3289 { "blockchain", getbestblockhash, },
3290 { "blockchain", getblock, },
3291 { "blockchain", getblockfrompeer, },
3292 { "blockchain", getblockchaininfo, },
3293 { "blockchain", getblockcount, },
3294 { "blockchain", getblockhash, },
3295 { "blockchain", getblockheader, },
3296 { "blockchain", getblockstats, },
3297 { "blockchain", getchaintips, },
3298 { "blockchain", getchaintxstats, },
3299 { "blockchain", getdifficulty, },
3300 { "blockchain", gettxout, },
3301 { "blockchain", gettxoutsetinfo, },
3302 { "blockchain", pruneblockchain, },
3303 { "blockchain", verifychain, },
3304 { "blockchain", preciousblock, },
3305 { "blockchain", scantxoutset, },
3306 { "blockchain", getblockfilter, },
3307 { "blockchain", dumptxoutset, },
3308 { "blockchain", loadtxoutset, },
3309 { "blockchain", getchainstates, },
3310
3311 /* Not shown in help */
3312 { "hidden", invalidateblock, },
3313 { "hidden", parkblock, },
3314 { "hidden", reconsiderblock, },
3315 { "hidden", syncwithvalidationinterfacequeue, },
3316 { "hidden", unparkblock, },
3317 { "hidden", waitfornewblock, },
3318 { "hidden", waitforblock, },
3319 { "hidden", waitforblockheight, },
3320 };
3321 // clang-format on
3322 for (const auto &c : commands) {
3323 t.appendCommand(c.name, &c);
3324 }
3325}
bool MoneyRange(const Amount nValue)
Definition: amount.h:177
static constexpr Amount MAX_MONEY
No amount larger than this (in satoshi) is valid.
Definition: amount.h:176
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: configfile.cpp:239
RPCHelpMan gettxout()
static RPCHelpMan getblock()
Definition: blockchain.cpp:706
static RPCHelpMan getdifficulty()
Definition: blockchain.cpp:463
static std::atomic< bool > g_scan_in_progress
static bool SetHasKeys(const std::set< T > &set)
static RPCHelpMan reconsiderblock()
static void InvalidateBlock(ChainstateManager &chainman, avalanche::Processor *const avalanche, const BlockHash &block_hash)
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:104
static RPCHelpMan syncwithvalidationinterfacequeue()
Definition: blockchain.cpp:444
static CBlockUndo GetUndoChecked(BlockManager &blockman, const CBlockIndex &blockindex)
Definition: blockchain.cpp:687
static RPCHelpMan getchaintips()
static RPCHelpMan loadtxoutset()
static RPCHelpMan gettxoutsetinfo()
Definition: blockchain.cpp:983
static RPCHelpMan getchainstates()
std::tuple< std::unique_ptr< CCoinsViewCursor >, CCoinsStats, const CBlockIndex * > PrepareUTXOSnapshot(Chainstate &chainstate, const std::function< void()> &interruption_point)
static RPCHelpMan getblockstats()
static CoinStatsHashType ParseHashType(const std::string &hash_type_input)
Definition: blockchain.cpp:969
static RPCHelpMan preciousblock()
static constexpr size_t PER_UTXO_OVERHEAD
double GetDifficulty(const CBlockIndex &blockindex)
Calculate the difficulty for a given block index.
Definition: blockchain.cpp:88
static RPCHelpMan scantxoutset()
static std::condition_variable cond_blockchange
Definition: blockchain.cpp:70
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:665
std::optional< int > GetPruneHeight(const BlockManager &blockman, const CChain &chain)
Definition: blockchain.cpp:857
static void ReconsiderBlock(ChainstateManager &chainman, avalanche::Processor *const avalanche, const BlockHash &block_hash)
static RPCHelpMan getblockfilter()
static RPCHelpMan getbestblockhash()
Definition: blockchain.cpp:238
RPCHelpMan getblockchaininfo()
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:322
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={})
static RPCHelpMan getblockfrompeer()
Definition: blockchain.cpp:483
static RPCHelpMan getblockhash()
Definition: blockchain.cpp:540
void RegisterBlockchainRPCCommands(CRPCTable &t)
static RPCHelpMan verifychain()
static std::atomic< bool > g_should_abort_scan
const std::vector< RPCResult > RPCHelpForChainstate
UniValue blockheaderToJSON(const CBlockIndex &tip, const CBlockIndex &blockindex)
Block header to JSON.
Definition: blockchain.cpp:147
RPCHelpMan unparkblock()
static RPCHelpMan waitforblockheight()
Definition: blockchain.cpp:384
static const CBlockIndex * ParseHashOrHeight(const UniValue &param, ChainstateManager &chainman)
Definition: blockchain.cpp:115
UniValue blockToJSON(BlockManager &blockman, const CBlock &block, const CBlockIndex &tip, const CBlockIndex &blockindex, TxVerbosity verbosity)
Block description to JSON.
Definition: blockchain.cpp:181
static RPCHelpMan pruneblockchain()
Definition: blockchain.cpp:895
static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange)
static RPCHelpMan getblockheader()
Definition: blockchain.cpp:569
RPCHelpMan parkblock()
static GlobalMutex cs_blockchange
Definition: blockchain.cpp:69
static RPCHelpMan dumptxoutset()
Serialize the UTXO set to a file for loading elsewhere.
static RPCHelpMan getblockcount()
Definition: blockchain.cpp:220
static RPCHelpMan waitfornewblock()
Definition: blockchain.cpp:265
void RPCNotifyBlockChange(const CBlockIndex *pindex)
Callback for when block tip changed.
Definition: blockchain.cpp:256
bool BlockFilterTypeByName(const std::string &name, BlockFilterType &filter_type)
Find a filter type by its human-readable name.
BlockFilterType
Definition: blockfilter.h:88
BlockFilterIndex * GetBlockFilterIndex(BlockFilterType filter_type)
Get a block filter index by type.
@ SCRIPTS
Scripts & signatures ok.
@ TREE
All parent headers found, difficulty matches, timestamp >= median previous, checkpoint.
const CBlockIndex * LastCommonAncestor(const CBlockIndex *pa, const CBlockIndex *pb)
Find the last common ancestor two blocks have.
Definition: chain.cpp:112
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:36
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:21
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:83
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: args.cpp:524
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:433
bool IsNull() const
Return true if the wrapped FILE* is nullptr, false otherwise.
Definition: streams.h:475
int fclose()
Definition: streams.h:448
Complete block filter struct as defined in BIP 157.
Definition: blockfilter.h:111
const std::vector< uint8_t > & GetEncodedFilter() const
Definition: blockfilter.h:134
BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of bloc...
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.
BlockHash GetHash() const
Definition: block.cpp:11
Definition: block.h:60
std::vector< CTransactionRef > vtx
Definition: block.h:63
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: blockindex.h:25
bool IsValid(enum BlockValidity nUpTo=BlockValidity::TRANSACTIONS) const EXCLUSIVE_LOCKS_REQUIRED(
Check whether this block index entry is valid up to the passed validity level.
Definition: blockindex.h:190
uint256 hashMerkleRoot
Definition: blockindex.h:74
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: blockindex.h:32
uint64_t m_chain_tx_count
(memory only) Number of transactions in the chain up to and including this block.
Definition: blockindex.h:67
CBlockHeader GetBlockHeader() const
Definition: blockindex.h:116
arith_uint256 nChainWork
(memory only) Total amount of work (expected number of hashes) in the chain up to and including this ...
Definition: blockindex.h:51
uint32_t nTime
Definition: blockindex.h:75
uint32_t nNonce
Definition: blockindex.h:77
int64_t GetBlockTime() const
Definition: blockindex.h:159
int64_t GetMedianTimePast() const
Definition: blockindex.h:171
uint32_t nBits
Definition: blockindex.h:76
unsigned int nTx
Number of transactions in this block.
Definition: blockindex.h:55
int32_t nVersion
block header
Definition: blockindex.h:73
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition: blockindex.cpp:62
BlockHash GetBlockHash() const
Definition: blockindex.h:129
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: blockindex.h:38
Undo information for a CBlock.
Definition: undo.h:72
std::vector< CTxUndo > vtxundo
Definition: undo.h:75
An in-memory indexed chain of blocks.
Definition: chain.h:138
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:154
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:62
int Height() const
Return the maximal height in the chain.
Definition: chain.h:190
const CBlockIndex * FindFork(const CBlockIndex *pindex) const
Find the last common block between this chain and a block index entry.
Definition: chain.cpp:49
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
Definition: chain.h:170
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
Definition: chainparams.h:86
std::string GetChainTypeString() const
Return the chain type string.
Definition: chainparams.h:134
const CBlock & GenesisBlock() const
Definition: chainparams.h:112
const CMessageHeader::MessageMagic & DiskMagic() const
Definition: chainparams.h:99
const ChainTxData & TxData() const
Definition: chainparams.h:158
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:358
BlockHash GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:217
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: coins.cpp:89
Cursor for iterating over CoinsView state.
Definition: coins.h:217
virtual void Next()=0
virtual bool Valid() const =0
virtual bool GetKey(COutPoint &key) const =0
virtual bool GetValue(Coin &coin) const =0
CCoinsViewCursor * Cursor() const override
Get a cursor to iterate over the whole state.
Definition: txdb.cpp:228
Abstract view on the open txout dataset.
Definition: coins.h:304
virtual BlockHash GetBestBlock() const
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:16
CCoinsView that brings transactions from a mempool into view.
Definition: txmempool.h:645
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
GetCoin, returning whether it exists and is not spent.
Definition: txmempool.cpp:779
Definition: net.h:838
bool GetNetworkActive() const
Definition: net.h:930
void SetNetworkActive(bool active)
Definition: net.cpp:2473
RPC command dispatcher.
Definition: server.h:194
void appendCommand(const std::string &name, const CRPCCommand *pcmd)
Appends a CRPCCommand to the dispatch table.
Definition: server.cpp:330
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:222
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:316
bool isSpent(const COutPoint &outpoint) const
Definition: txmempool.cpp:130
An output of a transaction.
Definition: transaction.h:128
CScript scriptPubKey
Definition: transaction.h:131
Amount nValue
Definition: transaction.h:130
Restore the UTXO in a Coin at a given COutPoint.
Definition: undo.h:61
RAII wrapper for VerifyDB: Verify consistency of the block and coin databases.
Definition: validation.h:641
VerifyDBResult VerifyDB(Chainstate &chainstate, 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:725
bool IsBlockAvalancheFinalized(const CBlockIndex *pindex) const EXCLUSIVE_LOCKS_REQUIRED(!cs_avalancheFinalizedBlockIndex)
Checks if a block is finalized by avalanche voting.
const std::optional< BlockHash > m_from_snapshot_blockhash
The blockhash which is the base of the snapshot this chainstate was created from.
Definition: validation.h:832
bool ActivateBestChain(BlockValidationState &state, std::shared_ptr< const CBlock > pblock=nullptr, avalanche::Processor *const avalanche=nullptr) EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex
Find the best known block, and make it the tip of the block chain.
CChain m_chain
The current chain of blockheaders we consult and build on.
Definition: validation.h:824
size_t m_coinstip_cache_size_bytes
The cache size of the in-memory coins view.
Definition: validation.h:884
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:851
size_t m_coinsdb_cache_size_bytes
The cache size of the on-disk coins view.
Definition: validation.h:881
void ForceFlushStateToDisk()
Unconditionally flush all changes to disk.
void UnparkBlockAndChildren(CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Remove parked status from a block and its descendants.
CCoinsViewDB & CoinsDB() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:858
ChainstateManager & m_chainman
The chainstate manager that owns this chainstate.
Definition: validation.h:787
bool AvalancheFinalizeBlock(CBlockIndex *pindex, avalanche::Processor &avalanche) EXCLUSIVE_LOCKS_REQUIRED(voi ClearAvalancheFinalizedBlock)() EXCLUSIVE_LOCKS_REQUIRED(!cs_avalancheFinalizedBlockIndex)
Mark a block as finalized by avalanche.
Definition: validation.h:987
node::BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all Chainstate instances.
Definition: validation.h:782
bool ParkBlock(BlockValidationState &state, CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex
Park a block.
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:1174
node::BlockMap & BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:1471
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:1445
kernel::Notifications & GetNotifications() const
Definition: validation.h:1303
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:1326
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1452
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1449
const CChainParams & GetParams() const
Definition: validation.h:1290
const Consensus::Params & GetConsensus() const
Definition: validation.h:1293
const CBlockIndex * GetAvalancheFinalizedTip() const
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:1446
Chainstate &InitializeChainstate(CTxMemPool *mempool) EXCLUSIVE_LOCKS_REQUIRED(std::vector< Chainstate * GetAll)()
Instantiate a new chainstate.
Definition: validation.h:1411
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1335
A UTXO entry.
Definition: coins.h:31
uint32_t GetHeight() const
Definition: coins.h:48
bool IsCoinBase() const
Definition: coins.h:49
CTxOut & GetTxOut()
Definition: coins.h:52
CoinsViewScanReserver()=default
Definition: config.h:19
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:118
Different type to mark Mutex at global scope.
Definition: sync.h:144
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(const Config &config, NodeId peer_id, const CBlockIndex &block_index)=0
Attempt to manually fetch block from a given peer.
auto Arg(size_t i) const
Helper to get a required or default-valued request argument.
Definition: util.h:416
RAII class that temporarily rolls back the local chain in it's constructor and rolls it forward again...
avalanche::Processor *const m_avalanche
const CBlockIndex & m_invalidate_index
TemporaryRollback(ChainstateManager &chainman, avalanche::Processor *const avalanche, const CBlockIndex &index)
ChainstateManager & m_chainman
void push_back(UniValue val)
Definition: univalue.cpp:96
const std::string & get_str() const
@ VNULL
Definition: univalue.h:30
@ VOBJ
Definition: univalue.h:31
@ VARR
Definition: univalue.h:32
bool isNull() const
Definition: univalue.h:104
size_t size() const
Definition: univalue.h:92
const std::vector< UniValue > & getValues() const
Int getInt() const
Definition: univalue.h:157
const UniValue & get_array() const
bool isNum() const
Definition: univalue.h:109
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:115
bool IsValid() const
Definition: validation.h:119
std::string GetRejectReason() const
Definition: validation.h:123
std::string ToString() const
Definition: validation.h:125
constexpr uint8_t * begin()
Definition: uint256.h:89
std::string ToString() const
Definition: uint256.h:84
std::string GetHex() const
Definition: uint256.cpp:10
std::string GetHex() const
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
std::string u8string() const
Definition: fs.h:72
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
Definition: blockstorage.h:114
bool ReadBlockUndo(CBlockUndo &blockundo, const CBlockIndex &index) const
CBlockIndex * LookupBlockIndex(const BlockHash &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
uint64_t GetPruneTarget() const
Attempt to stay below this number of bytes of block files.
Definition: blockstorage.h:359
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:356
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:31
256-bit opaque blob.
Definition: uint256.h:127
std::unique_ptr< CoinStatsIndex > g_coin_stats_index
The global UTXO set hash object.
void ScriptPubKeyToUniv(const CScript &scriptPubKey, UniValue &out, bool fIncludeHex)
Definition: core_write.cpp:194
TxVerbosity
Verbose level for block's transaction.
Definition: core_io.h:29
@ 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 TxToUniv(const CTransaction &tx, const BlockHash &hashBlock, UniValue &entry, bool include_hex=true, const CTxUndo *txundo=nullptr, TxVerbosity verbosity=TxVerbosity::SHOW_DETAILS, std::function< bool(const CTxOut &)> is_change_func={})
Definition: core_write.cpp:221
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:7
std::unique_ptr< Descriptor > InferDescriptor(const CScript &script, const SigningProvider &provider)
Find a descriptor for the specified script, using information from provider where possible.
int64_t NodeId
Definition: eviction.h:16
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition: hex_base.cpp:30
#define LogPrintLevel(category, level,...)
Definition: logging.h:437
#define LogPrint(category,...)
Definition: logging.h:452
unsigned int nHeight
static void pool cs
@ RPC
Definition: logging.h:76
@ NONE
Definition: logging.h:68
static path u8path(const std::string &utf8_str)
Definition: fs.h:90
static bool exists(const path &p)
Definition: fs.h:107
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition: fs.h:147
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:30
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:39
CoinStatsHashType
Definition: coinstats.h:24
Definition: messages.h:12
std::optional< kernel::CCoinsStats > GetUTXOStats(CCoinsView *view, BlockManager &blockman, kernel::CoinStatsHashType hash_type, const std::function< void()> &interruption_point, const CBlockIndex *pindex, bool index_requested)
Calculate statistics about the unspent transaction output set.
Definition: coinstats.cpp:17
bilingual_str ErrorString(const Result< T > &result)
Definition: result.h:90
std::string MakeUnorderedList(const std::vector< std::string > &items)
Create an unordered multi-line list of items.
Definition: string.h:132
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:315
@ NODE_NETWORK_LIMITED
Definition: protocol.h:365
@ NODE_NETWORK
Definition: protocol.h:342
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:58
@ RPC_MISC_ERROR
General application defined errors std::exception thrown in command handling.
Definition: protocol.h:38
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:46
@ RPC_INTERNAL_ERROR
Definition: protocol.h:33
@ RPC_DATABASE_ERROR
Database error.
Definition: protocol.h:48
@ RPC_DESERIALIZATION_ERROR
Error parsing or validating structure in raw format.
Definition: protocol.h:50
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:42
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:163
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:180
std::vector< CScript > EvalDescriptorStringOrObject(const UniValue &scanobject, FlatSigningProvider &provider)
Evaluate a descriptor given as a string, or as a {"desc":...,"range":...} object, with default range ...
Definition: util.cpp:1382
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:35
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded values (throws error if not hex).
Definition: util.cpp:86
size_t GetSerializeSize(const T &t)
Definition: serialize.h:1264
void WriteCompactSize(SizeComputer &os, uint64_t nSize)
Definition: serialize.h:1260
bool IsRPCRunning()
Query whether RPC is running.
Definition: server.cpp:381
ChainstateManager & EnsureAnyChainman(const std::any &context)
Definition: server_util.cpp:59
NodeContext & EnsureAnyNodeContext(const std::any &context)
Definition: server_util.cpp:21
CTxMemPool & EnsureMemPool(const NodeContext &node)
Definition: server_util.cpp:29
PeerManager & EnsurePeerman(const NodeContext &node)
Definition: server_util.cpp:72
ChainstateManager & EnsureChainman(const NodeContext &node)
Definition: server_util.cpp:52
ArgsManager & EnsureArgsman(const NodeContext &node)
Definition: server_util.cpp:41
CConnman & EnsureConnman(const NodeContext &node)
Definition: server_util.cpp:63
ArgsManager & EnsureAnyArgsman(const std::any &context)
Definition: server_util.cpp:48
Definition: amount.h:23
static constexpr Amount zero() noexcept
Definition: amount.h:36
A BlockHash is a unqiue identifier for a block.
Definition: blockhash.h:13
bool hasUndo() const
Definition: blockstatus.h:65
bool hasData() const
Definition: blockstatus.h:59
BlockHash hash
Definition: blockchain.cpp:65
Comparison function for sorting the getchaintips heads.
bool operator()(const CBlockIndex *a, const CBlockIndex *b) const
static std::string getTicker()
Definition: amount.h:163
@ 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:212
@ 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:214
std::string oneline_description
Should be empty unless it is supposed to override the auto-generated summary line.
Definition: util.h:149
bool skip_type_check
Definition: util.h:146
@ ELISION
Special type to denote elision (...)
@ NUM_TIME
Special numeric to denote unix epoch time.
@ STR_HEX
Special string with only hex chars.
@ STR_AMOUNT
Special string to represent a floating point amount.
A TxId is the identifier of a transaction.
Definition: txid.h:14
uint64_t nDiskSize
Definition: coinstats.h:37
Amount total_unspendables_scripts
Total cumulative amount of outputs sent to unspendable scripts (OP_RETURN for example) up to and incl...
Definition: coinstats.h:69
Amount total_coinbase_amount
Total cumulative amount of coinbase outputs up to and including this block.
Definition: coinstats.h:62
Amount total_unspendables_genesis_block
The unspendable coinbase amount from the genesis block.
Definition: coinstats.h:64
uint64_t coins_count
The number of coins contained.
Definition: coinstats.h:42
uint64_t nTransactions
Definition: coinstats.h:33
uint64_t nTransactionOutputs
Definition: coinstats.h:34
uint64_t nBogoSize
Definition: coinstats.h:35
bool index_used
Signals if the coinstatsindex was used to retrieve the statistics.
Definition: coinstats.h:45
Amount total_unspendables_bip30
The two unspendable coinbase outputs total amount caused by BIP30.
Definition: coinstats.h:66
Amount total_prevout_spent_amount
Total cumulative amount of prevouts spent up to and including this block.
Definition: coinstats.h:56
BlockHash hashBlock
Definition: coinstats.h:32
Amount total_unspendables_unclaimed_rewards
Total cumulative amount of coins lost due to unclaimed miner rewards up to and including this block.
Definition: coinstats.h:72
uint256 hashSerialized
Definition: coinstats.h:36
std::optional< Amount > total_amount
The total amount, or nullopt if an overflow occurred calculating it.
Definition: coinstats.h:39
Amount total_new_outputs_ex_coinbase_amount
Total cumulative amount of outputs created up to and including this block.
Definition: coinstats.h:59
Amount total_unspendable_amount
Total cumulative amount of unspendable coins up to and including this block.
Definition: coinstats.h:54
NodeContext struct containing references to chain state and connection state.
Definition: context.h:49
#define WAIT_LOCK(cs, name)
Definition: sync.h:317
#define AssertLockNotHeld(cs)
Definition: sync.h:163
#define LOCK(cs)
Definition: sync.h:306
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:357
static int count
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:56
#define LOG_TIME_SECONDS(end_msg)
Definition: timer.h:103
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1203
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:68
static const uint32_t MEMPOOL_HEIGHT
Fake height value used in Coins to signify they are only in the memory pool(since 0....
Definition: txmempool.h:56
uint256 uint256S(const char *str)
uint256 from const char *.
Definition: uint256.h:141
const UniValue NullUniValue
Definition: univalue.cpp:16
Amount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams)
double GuessVerificationProgress(const ChainTxData &data, const CBlockIndex *pindex)
Guess how far we are in the verification process at the given block index require cs_main if pindex h...
const std::vector< std::string > CHECKLEVEL_DOC
Documentation for argument 'checklevel'.
Definition: validation.cpp:95
void PruneBlockFilesManual(Chainstate &active_chainstate, int nManualPruneHeight)
Prune block files up to a given height.
AssertLockHeld(pool.cs)
static constexpr int DEFAULT_CHECKLEVEL
Definition: validation.h:93
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:91
static const signed int DEFAULT_CHECKBLOCKS
Definition: validation.h:92
bilingual_str GetWarnings(bool verbose)
Format a string that describes several potential problems detected by the core.
Definition: warnings.cpp:43