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