Bitcoin ABC 0.31.0
P2P Digital Currency
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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
8#include <blockfilter.h>
9#include <chain.h>
10#include <chainparams.h>
11#include <coins.h>
12#include <common/args.h>
13#include <config.h>
14#include <consensus/amount.h>
15#include <consensus/params.h>
17#include <core_io.h>
18#include <hash.h>
21#include <logging/timer.h>
22#include <net.h>
23#include <net_processing.h>
24#include <node/blockstorage.h>
25#include <node/coinstats.h>
26#include <node/context.h>
27#include <node/utxo_snapshot.h>
29#include <rpc/server.h>
30#include <rpc/server_util.h>
31#include <rpc/util.h>
32#include <script/descriptor.h>
33#include <streams.h>
34#include <txdb.h>
35#include <txmempool.h>
36#include <undo.h>
37#include <util/check.h>
38#include <util/fs.h>
39#include <util/strencodings.h>
40#include <util/translation.h>
41#include <validation.h>
42#include <validationinterface.h>
43#include <warnings.h>
44
45#include <condition_variable>
46#include <cstdint>
47#include <memory>
48#include <mutex>
49
52
57
60 int height;
61};
62
64static std::condition_variable cond_blockchange;
66
70double GetDifficulty(const CBlockIndex *blockindex) {
71 CHECK_NONFATAL(blockindex);
72
73 int nShift = (blockindex->nBits >> 24) & 0xff;
74 double dDiff = double(0x0000ffff) / double(blockindex->nBits & 0x00ffffff);
75
76 while (nShift < 29) {
77 dDiff *= 256.0;
78 nShift++;
79 }
80 while (nShift > 29) {
81 dDiff /= 256.0;
82 nShift--;
83 }
84
85 return dDiff;
86}
87
89 const CBlockIndex *blockindex,
90 const CBlockIndex *&next) {
91 next = tip->GetAncestor(blockindex->nHeight + 1);
92 if (next && next->pprev == blockindex) {
93 return tip->nHeight - blockindex->nHeight + 1;
94 }
95 next = nullptr;
96 return blockindex == tip ? 1 : -1;
97}
98
99static const CBlockIndex *ParseHashOrHeight(const UniValue &param,
100 ChainstateManager &chainman) {
102 CChain &active_chain = chainman.ActiveChain();
103
104 if (param.isNum()) {
105 const int height{param.getInt<int>()};
106 if (height < 0) {
107 throw JSONRPCError(
109 strprintf("Target block height %d is negative", height));
110 }
111 const int current_tip{active_chain.Height()};
112 if (height > current_tip) {
113 throw JSONRPCError(
115 strprintf("Target block height %d after current tip %d", height,
116 current_tip));
117 }
118
119 return active_chain[height];
120 } else {
121 const BlockHash hash{ParseHashV(param, "hash_or_height")};
122 const CBlockIndex *pindex = chainman.m_blockman.LookupBlockIndex(hash);
123
124 if (!pindex) {
125 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
126 }
127
128 return pindex;
129 }
130}
132 const CBlockIndex *blockindex) {
133 // Serialize passed information without accessing chain state of the active
134 // chain!
135 // For performance reasons
137
138 UniValue result(UniValue::VOBJ);
139 result.pushKV("hash", blockindex->GetBlockHash().GetHex());
140 const CBlockIndex *pnext;
141 int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
142 result.pushKV("confirmations", confirmations);
143 result.pushKV("height", blockindex->nHeight);
144 result.pushKV("version", blockindex->nVersion);
145 result.pushKV("versionHex", strprintf("%08x", blockindex->nVersion));
146 result.pushKV("merkleroot", blockindex->hashMerkleRoot.GetHex());
147 result.pushKV("time", int64_t(blockindex->nTime));
148 result.pushKV("mediantime", int64_t(blockindex->GetMedianTimePast()));
149 result.pushKV("nonce", uint64_t(blockindex->nNonce));
150 result.pushKV("bits", strprintf("%08x", blockindex->nBits));
151 result.pushKV("difficulty", GetDifficulty(blockindex));
152 result.pushKV("chainwork", blockindex->nChainWork.GetHex());
153 result.pushKV("nTx", uint64_t(blockindex->nTx));
154
155 if (blockindex->pprev) {
156 result.pushKV("previousblockhash",
157 blockindex->pprev->GetBlockHash().GetHex());
158 }
159 if (pnext) {
160 result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
161 }
162 return result;
163}
164
165UniValue blockToJSON(BlockManager &blockman, const CBlock &block,
166 const CBlockIndex *tip, const CBlockIndex *blockindex,
167 bool txDetails) {
168 UniValue result = blockheaderToJSON(tip, blockindex);
169
170 result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION));
172 if (txDetails) {
173 CBlockUndo blockUndo;
174 const bool is_not_pruned{
175 WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))};
176 const bool have_undo{is_not_pruned &&
177 blockman.UndoReadFromDisk(blockUndo, *blockindex)};
178 for (size_t i = 0; i < block.vtx.size(); ++i) {
179 const CTransactionRef &tx = block.vtx.at(i);
180 // coinbase transaction (i == 0) doesn't have undo data
181 const CTxUndo *txundo =
182 (have_undo && i) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
184 TxToUniv(*tx, BlockHash(), objTx, true, RPCSerializationFlags(),
185 txundo);
186 txs.push_back(objTx);
187 }
188 } else {
189 for (const CTransactionRef &tx : block.vtx) {
190 txs.push_back(tx->GetId().GetHex());
191 }
192 }
193 result.pushKV("tx", txs);
194
195 return result;
196}
197
199 return RPCHelpMan{
200 "getblockcount",
201 "Returns the height of the most-work fully-validated chain.\n"
202 "The genesis block has height 0.\n",
203 {},
204 RPCResult{RPCResult::Type::NUM, "", "The current block count"},
205 RPCExamples{HelpExampleCli("getblockcount", "") +
206 HelpExampleRpc("getblockcount", "")},
207 [&](const RPCHelpMan &self, const Config &config,
208 const JSONRPCRequest &request) -> UniValue {
209 ChainstateManager &chainman = EnsureAnyChainman(request.context);
210 LOCK(cs_main);
211 return chainman.ActiveHeight();
212 },
213 };
214}
215
217 return RPCHelpMan{
218 "getbestblockhash",
219 "Returns the hash of the best (tip) block in the "
220 "most-work fully-validated chain.\n",
221 {},
222 RPCResult{RPCResult::Type::STR_HEX, "", "the block hash, hex-encoded"},
223 RPCExamples{HelpExampleCli("getbestblockhash", "") +
224 HelpExampleRpc("getbestblockhash", "")},
225 [&](const RPCHelpMan &self, const Config &config,
226 const JSONRPCRequest &request) -> UniValue {
227 ChainstateManager &chainman = EnsureAnyChainman(request.context);
228 LOCK(cs_main);
229 return chainman.ActiveTip()->GetBlockHash().GetHex();
230 },
231 };
232}
233
235 if (pindex) {
237 latestblock.hash = pindex->GetBlockHash();
238 latestblock.height = pindex->nHeight;
239 }
240 cond_blockchange.notify_all();
241}
242
244 return RPCHelpMan{
245 "waitfornewblock",
246 "Waits for a specific new block and returns useful info about it.\n"
247 "\nReturns the current block on timeout or exit.\n",
248 {
249 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0},
250 "Time in milliseconds to wait for a response. 0 indicates no "
251 "timeout."},
252 },
254 "",
255 "",
256 {
257 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
258 {RPCResult::Type::NUM, "height", "Block height"},
259 }},
260 RPCExamples{HelpExampleCli("waitfornewblock", "1000") +
261 HelpExampleRpc("waitfornewblock", "1000")},
262 [&](const RPCHelpMan &self, const Config &config,
263 const JSONRPCRequest &request) -> UniValue {
264 int timeout = 0;
265 if (!request.params[0].isNull()) {
266 timeout = request.params[0].getInt<int>();
267 }
268
269 CUpdatedBlock block;
270 {
272 block = latestblock;
273 if (timeout) {
274 cond_blockchange.wait_for(
275 lock, std::chrono::milliseconds(timeout),
277 return latestblock.height != block.height ||
278 latestblock.hash != block.hash ||
279 !IsRPCRunning();
280 });
281 } else {
282 cond_blockchange.wait(
283 lock,
285 return latestblock.height != block.height ||
286 latestblock.hash != block.hash ||
287 !IsRPCRunning();
288 });
289 }
290 block = latestblock;
291 }
293 ret.pushKV("hash", block.hash.GetHex());
294 ret.pushKV("height", block.height);
295 return ret;
296 },
297 };
298}
299
301 return RPCHelpMan{
302 "waitforblock",
303 "Waits for a specific new block and returns useful info about it.\n"
304 "\nReturns the current block on timeout or exit.\n",
305 {
307 "Block hash to wait for."},
308 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0},
309 "Time in milliseconds to wait for a response. 0 indicates no "
310 "timeout."},
311 },
313 "",
314 "",
315 {
316 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
317 {RPCResult::Type::NUM, "height", "Block height"},
318 }},
319 RPCExamples{HelpExampleCli("waitforblock",
320 "\"0000000000079f8ef3d2c688c244eb7a4570b24c9"
321 "ed7b4a8c619eb02596f8862\" 1000") +
322 HelpExampleRpc("waitforblock",
323 "\"0000000000079f8ef3d2c688c244eb7a4570b24c9"
324 "ed7b4a8c619eb02596f8862\", 1000")},
325 [&](const RPCHelpMan &self, const Config &config,
326 const JSONRPCRequest &request) -> UniValue {
327 int timeout = 0;
328
329 BlockHash hash(ParseHashV(request.params[0], "blockhash"));
330
331 if (!request.params[1].isNull()) {
332 timeout = request.params[1].getInt<int>();
333 }
334
335 CUpdatedBlock block;
336 {
338 if (timeout) {
339 cond_blockchange.wait_for(
340 lock, std::chrono::milliseconds(timeout),
342 return latestblock.hash == hash || !IsRPCRunning();
343 });
344 } else {
345 cond_blockchange.wait(
346 lock,
348 return latestblock.hash == hash || !IsRPCRunning();
349 });
350 }
351 block = latestblock;
352 }
353
355 ret.pushKV("hash", block.hash.GetHex());
356 ret.pushKV("height", block.height);
357 return ret;
358 },
359 };
360}
361
363 return RPCHelpMan{
364 "waitforblockheight",
365 "Waits for (at least) block height and returns the height and "
366 "hash\nof the current tip.\n"
367 "\nReturns the current block on timeout or exit.\n",
368 {
370 "Block height to wait for."},
371 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0},
372 "Time in milliseconds to wait for a response. 0 indicates no "
373 "timeout."},
374 },
376 "",
377 "",
378 {
379 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
380 {RPCResult::Type::NUM, "height", "Block height"},
381 }},
382 RPCExamples{HelpExampleCli("waitforblockheight", "100 1000") +
383 HelpExampleRpc("waitforblockheight", "100, 1000")},
384 [&](const RPCHelpMan &self, const Config &config,
385 const JSONRPCRequest &request) -> UniValue {
386 int timeout = 0;
387
388 int height = request.params[0].getInt<int>();
389
390 if (!request.params[1].isNull()) {
391 timeout = request.params[1].getInt<int>();
392 }
393
394 CUpdatedBlock block;
395 {
397 if (timeout) {
398 cond_blockchange.wait_for(
399 lock, std::chrono::milliseconds(timeout),
401 return latestblock.height >= height ||
402 !IsRPCRunning();
403 });
404 } else {
405 cond_blockchange.wait(
406 lock,
408 return latestblock.height >= height ||
409 !IsRPCRunning();
410 });
411 }
412 block = latestblock;
413 }
415 ret.pushKV("hash", block.hash.GetHex());
416 ret.pushKV("height", block.height);
417 return ret;
418 },
419 };
420}
421
423 return RPCHelpMan{
424 "syncwithvalidationinterfacequeue",
425 "Waits for the validation interface queue to catch up on everything "
426 "that was there when we entered this function.\n",
427 {},
429 RPCExamples{HelpExampleCli("syncwithvalidationinterfacequeue", "") +
430 HelpExampleRpc("syncwithvalidationinterfacequeue", "")},
431 [&](const RPCHelpMan &self, const Config &config,
432 const JSONRPCRequest &request) -> UniValue {
434 return NullUniValue;
435 },
436 };
437}
438
440 return RPCHelpMan{
441 "getdifficulty",
442 "Returns the proof-of-work difficulty as a multiple of the minimum "
443 "difficulty.\n",
444 {},
446 "the proof-of-work difficulty as a multiple of the minimum "
447 "difficulty."},
448 RPCExamples{HelpExampleCli("getdifficulty", "") +
449 HelpExampleRpc("getdifficulty", "")},
450 [&](const RPCHelpMan &self, const Config &config,
451 const JSONRPCRequest &request) -> UniValue {
452 ChainstateManager &chainman = EnsureAnyChainman(request.context);
453 LOCK(cs_main);
454 return GetDifficulty(chainman.ActiveTip());
455 },
456 };
457}
458
460 return RPCHelpMan{
461 "getblockfrompeer",
462 "Attempt to fetch block from a given peer.\n"
463 "\nWe must have the header for this block, e.g. using submitheader.\n"
464 "Subsequent calls for the same block may cause the response from the "
465 "previous peer to be ignored.\n"
466 "\nReturns an empty JSON object if the request was successfully "
467 "scheduled.",
468 {
470 "The block hash to try to fetch"},
472 "The peer to fetch it from (see getpeerinfo for peer IDs)"},
473 },
474 RPCResult{RPCResult::Type::OBJ, "", /*optional=*/false, "", {}},
475 RPCExamples{HelpExampleCli("getblockfrompeer",
476 "\"00000000c937983704a73af28acdec37b049d214a"
477 "dbda81d7e2a3dd146f6ed09\" 0") +
478 HelpExampleRpc("getblockfrompeer",
479 "\"00000000c937983704a73af28acdec37b049d214a"
480 "dbda81d7e2a3dd146f6ed09\" 0")},
481 [&](const RPCHelpMan &self, const Config &config,
482 const JSONRPCRequest &request) -> UniValue {
483 const NodeContext &node = EnsureAnyNodeContext(request.context);
485 PeerManager &peerman = EnsurePeerman(node);
486
487 const BlockHash block_hash{
488 ParseHashV(request.params[0], "blockhash")};
489 const NodeId peer_id{request.params[1].getInt<int64_t>()};
490
491 const CBlockIndex *const index = WITH_LOCK(
492 cs_main,
493 return chainman.m_blockman.LookupBlockIndex(block_hash););
494
495 if (!index) {
496 throw JSONRPCError(RPC_MISC_ERROR, "Block header missing");
497 }
498
499 if (WITH_LOCK(::cs_main, return index->nStatus.hasData())) {
500 throw JSONRPCError(RPC_MISC_ERROR, "Block already downloaded");
501 }
502
503 if (const auto err{peerman.FetchBlock(config, peer_id, *index)}) {
504 throw JSONRPCError(RPC_MISC_ERROR, err.value());
505 }
506 return UniValue::VOBJ;
507 },
508 };
509}
510
512 return RPCHelpMan{
513 "getblockhash",
514 "Returns hash of block in best-block-chain at height provided.\n",
515 {
517 "The height index"},
518 },
519 RPCResult{RPCResult::Type::STR_HEX, "", "The block hash"},
520 RPCExamples{HelpExampleCli("getblockhash", "1000") +
521 HelpExampleRpc("getblockhash", "1000")},
522 [&](const RPCHelpMan &self, const Config &config,
523 const JSONRPCRequest &request) -> UniValue {
524 ChainstateManager &chainman = EnsureAnyChainman(request.context);
525 LOCK(cs_main);
526 const CChain &active_chain = chainman.ActiveChain();
527
528 int nHeight = request.params[0].getInt<int>();
529 if (nHeight < 0 || nHeight > active_chain.Height()) {
531 "Block height out of range");
532 }
533
534 const CBlockIndex *pblockindex = active_chain[nHeight];
535 return pblockindex->GetBlockHash().GetHex();
536 },
537 };
538}
539
541 return RPCHelpMan{
542 "getblockheader",
543 "If verbose is false, returns a string that is serialized, hex-encoded "
544 "data for blockheader 'hash'.\n"
545 "If verbose is true, returns an Object with information about "
546 "blockheader <hash>.\n",
547 {
549 "The block hash"},
550 {"verbose", RPCArg::Type::BOOL, RPCArg::Default{true},
551 "true for a json object, false for the hex-encoded data"},
552 },
553 {
554 RPCResult{
555 "for verbose = true",
557 "",
558 "",
559 {
561 "the block hash (same as provided)"},
562 {RPCResult::Type::NUM, "confirmations",
563 "The number of confirmations, or -1 if the block is not "
564 "on the main chain"},
565 {RPCResult::Type::NUM, "height",
566 "The block height or index"},
567 {RPCResult::Type::NUM, "version", "The block version"},
568 {RPCResult::Type::STR_HEX, "versionHex",
569 "The block version formatted in hexadecimal"},
570 {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
572 "The block time expressed in " + UNIX_EPOCH_TIME},
573 {RPCResult::Type::NUM_TIME, "mediantime",
574 "The median block time expressed in " + UNIX_EPOCH_TIME},
575 {RPCResult::Type::NUM, "nonce", "The nonce"},
576 {RPCResult::Type::STR_HEX, "bits", "The bits"},
577 {RPCResult::Type::NUM, "difficulty", "The difficulty"},
578 {RPCResult::Type::STR_HEX, "chainwork",
579 "Expected number of hashes required to produce the "
580 "current chain"},
581 {RPCResult::Type::NUM, "nTx",
582 "The number of transactions in the block"},
583 {RPCResult::Type::STR_HEX, "previousblockhash",
584 /* optional */ true,
585 "The hash of the previous block (if available)"},
586 {RPCResult::Type::STR_HEX, "nextblockhash",
587 /* optional */ true,
588 "The hash of the next block (if available)"},
589 }},
590 RPCResult{"for verbose=false", RPCResult::Type::STR_HEX, "",
591 "A string that is serialized, hex-encoded data for block "
592 "'hash'"},
593 },
594 RPCExamples{HelpExampleCli("getblockheader",
595 "\"00000000c937983704a73af28acdec37b049d214a"
596 "dbda81d7e2a3dd146f6ed09\"") +
597 HelpExampleRpc("getblockheader",
598 "\"00000000c937983704a73af28acdec37b049d214a"
599 "dbda81d7e2a3dd146f6ed09\"")},
600 [&](const RPCHelpMan &self, const Config &config,
601 const JSONRPCRequest &request) -> UniValue {
602 BlockHash hash(ParseHashV(request.params[0], "hash"));
603
604 bool fVerbose = true;
605 if (!request.params[1].isNull()) {
606 fVerbose = request.params[1].get_bool();
607 }
608
609 const CBlockIndex *pblockindex;
610 const CBlockIndex *tip;
611 {
612 ChainstateManager &chainman =
613 EnsureAnyChainman(request.context);
614 LOCK(cs_main);
615 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
616 tip = chainman.ActiveTip();
617 }
618
619 if (!pblockindex) {
621 "Block not found");
622 }
623
624 if (!fVerbose) {
626 ssBlock << pblockindex->GetBlockHeader();
627 std::string strHex = HexStr(ssBlock);
628 return strHex;
629 }
630
631 return blockheaderToJSON(tip, pblockindex);
632 },
633 };
634}
635
637 const CBlockIndex *pblockindex) {
638 CBlock block;
639 {
640 LOCK(cs_main);
641 if (blockman.IsBlockPruned(pblockindex)) {
643 "Block not available (pruned data)");
644 }
645 }
646
647 if (!blockman.ReadBlockFromDisk(block, *pblockindex)) {
648 // Block not found on disk. This could be because we have the block
649 // header in our index but not yet have the block or did not accept the
650 // block. Or if the block was pruned right after we released the lock
651 // above.
652 throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
653 }
654
655 return block;
656}
657
659 const CBlockIndex *pblockindex) {
660 CBlockUndo blockUndo;
661
662 {
663 LOCK(cs_main);
664 if (blockman.IsBlockPruned(pblockindex)) {
666 "Undo data not available (pruned data)");
667 }
668 }
669
670 if (!blockman.UndoReadFromDisk(blockUndo, *pblockindex)) {
671 throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
672 }
673
674 return blockUndo;
675}
676
678 return RPCHelpMan{
679 "getblock",
680 "If verbosity is 0 or false, returns a string that is serialized, "
681 "hex-encoded data for block 'hash'.\n"
682 "If verbosity is 1 or true, returns an Object with information about "
683 "block <hash>.\n"
684 "If verbosity is 2, returns an Object with information about block "
685 "<hash> and information about each transaction.\n",
686 {
688 "The block hash"},
689 {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1},
690 "0 for hex-encoded data, 1 for a json object, and 2 for json "
691 "object with transaction data",
693 },
694 {
695 RPCResult{"for verbosity = 0", RPCResult::Type::STR_HEX, "",
696 "A string that is serialized, hex-encoded data for block "
697 "'hash'"},
698 RPCResult{
699 "for verbosity = 1",
701 "",
702 "",
703 {
705 "the block hash (same as provided)"},
706 {RPCResult::Type::NUM, "confirmations",
707 "The number of confirmations, or -1 if the block is not "
708 "on the main chain"},
709 {RPCResult::Type::NUM, "size", "The block size"},
710 {RPCResult::Type::NUM, "height",
711 "The block height or index"},
712 {RPCResult::Type::NUM, "version", "The block version"},
713 {RPCResult::Type::STR_HEX, "versionHex",
714 "The block version formatted in hexadecimal"},
715 {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
717 "tx",
718 "The transaction ids",
719 {{RPCResult::Type::STR_HEX, "", "The transaction id"}}},
721 "The block time expressed in " + UNIX_EPOCH_TIME},
722 {RPCResult::Type::NUM_TIME, "mediantime",
723 "The median block time expressed in " + UNIX_EPOCH_TIME},
724 {RPCResult::Type::NUM, "nonce", "The nonce"},
725 {RPCResult::Type::STR_HEX, "bits", "The bits"},
726 {RPCResult::Type::NUM, "difficulty", "The difficulty"},
727 {RPCResult::Type::STR_HEX, "chainwork",
728 "Expected number of hashes required to produce the chain "
729 "up to this block (in hex)"},
730 {RPCResult::Type::NUM, "nTx",
731 "The number of transactions in the block"},
732 {RPCResult::Type::STR_HEX, "previousblockhash",
733 /* optional */ true,
734 "The hash of the previous block (if available)"},
735 {RPCResult::Type::STR_HEX, "nextblockhash",
736 /* optional */ true,
737 "The hash of the next block (if available)"},
738 }},
739 RPCResult{"for verbosity = 2",
741 "",
742 "",
743 {
745 "Same output as verbosity = 1"},
747 "tx",
748 "",
749 {
751 "",
752 "",
753 {
755 "The transactions in the format of the "
756 "getrawtransaction RPC. Different from "
757 "verbosity = 1 \"tx\" result"},
759 "The transaction fee in " +
761 ", omitted if block undo data is not "
762 "available"},
763 }},
764 }},
765 }},
766 },
768 HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d"
769 "214adbda81d7e2a3dd146f6ed09\"") +
770 HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d"
771 "214adbda81d7e2a3dd146f6ed09\"")},
772 [&](const RPCHelpMan &self, const Config &config,
773 const JSONRPCRequest &request) -> UniValue {
774 BlockHash hash(ParseHashV(request.params[0], "blockhash"));
775
776 int verbosity = 1;
777 if (!request.params[1].isNull()) {
778 if (request.params[1].isNum()) {
779 verbosity = request.params[1].getInt<int>();
780 } else {
781 verbosity = request.params[1].get_bool() ? 1 : 0;
782 }
783 }
784
785 const CBlockIndex *pblockindex;
786 const CBlockIndex *tip;
787 ChainstateManager &chainman = EnsureAnyChainman(request.context);
788 {
789 LOCK(cs_main);
790 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
791 tip = chainman.ActiveTip();
792
793 if (!pblockindex) {
795 "Block not found");
796 }
797 }
798
799 const CBlock block =
800 GetBlockChecked(chainman.m_blockman, pblockindex);
801
802 if (verbosity <= 0) {
803 CDataStream ssBlock(SER_NETWORK,
805 ssBlock << block;
806 std::string strHex = HexStr(ssBlock);
807 return strHex;
808 }
809
810 return blockToJSON(chainman.m_blockman, block, tip, pblockindex,
811 verbosity >= 2);
812 },
813 };
814}
815
817 return RPCHelpMan{
818 "pruneblockchain",
819 "",
820 {
822 "The block height to prune up to. May be set to a discrete "
823 "height, or to a " +
825 "\n"
826 " to prune blocks whose block time is at "
827 "least 2 hours older than the provided timestamp."},
828 },
829 RPCResult{RPCResult::Type::NUM, "", "Height of the last block pruned"},
830 RPCExamples{HelpExampleCli("pruneblockchain", "1000") +
831 HelpExampleRpc("pruneblockchain", "1000")},
832 [&](const RPCHelpMan &self, const Config &config,
833 const JSONRPCRequest &request) -> UniValue {
834 ChainstateManager &chainman = EnsureAnyChainman(request.context);
835 if (!chainman.m_blockman.IsPruneMode()) {
836 throw JSONRPCError(
838 "Cannot prune blocks because node is not in prune mode.");
839 }
840
841 LOCK(cs_main);
842 Chainstate &active_chainstate = chainman.ActiveChainstate();
843 CChain &active_chain = active_chainstate.m_chain;
844
845 int heightParam = request.params[0].getInt<int>();
846 if (heightParam < 0) {
848 "Negative block height.");
849 }
850
851 // Height value more than a billion is too high to be a block
852 // height, and too low to be a block time (corresponds to timestamp
853 // from Sep 2001).
854 if (heightParam > 1000000000) {
855 // Add a 2 hour buffer to include blocks which might have had
856 // old timestamps
857 const CBlockIndex *pindex = active_chain.FindEarliestAtLeast(
858 heightParam - TIMESTAMP_WINDOW, 0);
859 if (!pindex) {
861 "Could not find block with at least the "
862 "specified timestamp.");
863 }
864 heightParam = pindex->nHeight;
865 }
866
867 unsigned int height = (unsigned int)heightParam;
868 unsigned int chainHeight = (unsigned int)active_chain.Height();
869 if (chainHeight < config.GetChainParams().PruneAfterHeight()) {
871 "Blockchain is too short for pruning.");
872 } else if (height > chainHeight) {
873 throw JSONRPCError(
875 "Blockchain is shorter than the attempted prune height.");
876 } else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
878 "Attempt to prune blocks close to the tip. "
879 "Retaining the minimum number of blocks.\n");
880 height = chainHeight - MIN_BLOCKS_TO_KEEP;
881 }
882
883 PruneBlockFilesManual(active_chainstate, height);
884 const CBlockIndex &block{*CHECK_NONFATAL(active_chain.Tip())};
885 return block.nStatus.hasData() ? active_chainstate.m_blockman
886 .GetFirstStoredBlock(block)
887 ->nHeight -
888 1
889 : block.nHeight;
890 },
891 };
892}
893
894static CoinStatsHashType ParseHashType(const std::string &hash_type_input) {
895 if (hash_type_input == "hash_serialized") {
896 return CoinStatsHashType::HASH_SERIALIZED;
897 } else if (hash_type_input == "muhash") {
898 return CoinStatsHashType::MUHASH;
899 } else if (hash_type_input == "none") {
901 } else {
902 throw JSONRPCError(
904 strprintf("%s is not a valid hash_type", hash_type_input));
905 }
906}
907
909 return RPCHelpMan{
910 "gettxoutsetinfo",
911 "Returns statistics about the unspent transaction output set.\n"
912 "Note this call may take some time if you are not using "
913 "coinstatsindex.\n",
914 {
915 {"hash_type", RPCArg::Type::STR, RPCArg::Default{"hash_serialized"},
916 "Which UTXO set hash should be calculated. Options: "
917 "'hash_serialized' (the legacy algorithm), 'muhash', 'none'."},
919 "The block hash or height of the target height (only available "
920 "with coinstatsindex).",
922 .type_str = {"", "string or numeric"}}},
923 {"use_index", RPCArg::Type::BOOL, RPCArg::Default{true},
924 "Use coinstatsindex, if available."},
925 },
926 RPCResult{
928 "",
929 "",
930 {
931 {RPCResult::Type::NUM, "height",
932 "The current block height (index)"},
933 {RPCResult::Type::STR_HEX, "bestblock",
934 "The hash of the block at the tip of the chain"},
935 {RPCResult::Type::NUM, "txouts",
936 "The number of unspent transaction outputs"},
937 {RPCResult::Type::NUM, "bogosize",
938 "Database-independent, meaningless metric indicating "
939 "the UTXO set size"},
940 {RPCResult::Type::STR_HEX, "hash_serialized",
941 /* optional */ true,
942 "The serialized hash (only present if 'hash_serialized' "
943 "hash_type is chosen)"},
944 {RPCResult::Type::STR_HEX, "muhash", /* optional */ true,
945 "The serialized hash (only present if 'muhash' "
946 "hash_type is chosen)"},
947 {RPCResult::Type::NUM, "transactions",
948 "The number of transactions with unspent outputs (not "
949 "available when coinstatsindex is used)"},
950 {RPCResult::Type::NUM, "disk_size",
951 "The estimated size of the chainstate on disk (not "
952 "available when coinstatsindex is used)"},
953 {RPCResult::Type::STR_AMOUNT, "total_amount",
954 "The total amount"},
955 {RPCResult::Type::STR_AMOUNT, "total_unspendable_amount",
956 "The total amount of coins permanently excluded from the UTXO "
957 "set (only available if coinstatsindex is used)"},
959 "block_info",
960 "Info on amounts in the block at this block height (only "
961 "available if coinstatsindex is used)",
962 {{RPCResult::Type::STR_AMOUNT, "prevout_spent",
963 "Total amount of all prevouts spent in this block"},
964 {RPCResult::Type::STR_AMOUNT, "coinbase",
965 "Coinbase subsidy amount of this block"},
966 {RPCResult::Type::STR_AMOUNT, "new_outputs_ex_coinbase",
967 "Total amount of new outputs created by this block"},
968 {RPCResult::Type::STR_AMOUNT, "unspendable",
969 "Total amount of unspendable outputs created in this block"},
971 "unspendables",
972 "Detailed view of the unspendable categories",
973 {
974 {RPCResult::Type::STR_AMOUNT, "genesis_block",
975 "The unspendable amount of the Genesis block subsidy"},
977 "Transactions overridden by duplicates (no longer "
978 "possible with BIP30)"},
979 {RPCResult::Type::STR_AMOUNT, "scripts",
980 "Amounts sent to scripts that are unspendable (for "
981 "example OP_RETURN outputs)"},
982 {RPCResult::Type::STR_AMOUNT, "unclaimed_rewards",
983 "Fee rewards that miners did not claim in their "
984 "coinbase transaction"},
985 }}}},
986 }},
988 HelpExampleCli("gettxoutsetinfo", "") +
989 HelpExampleCli("gettxoutsetinfo", R"("none")") +
990 HelpExampleCli("gettxoutsetinfo", R"("none" 1000)") +
992 "gettxoutsetinfo",
993 R"("none" '"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"')") +
994 HelpExampleRpc("gettxoutsetinfo", "") +
995 HelpExampleRpc("gettxoutsetinfo", R"("none")") +
996 HelpExampleRpc("gettxoutsetinfo", R"("none", 1000)") +
998 "gettxoutsetinfo",
999 R"("none", "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09")")},
1000 [&](const RPCHelpMan &self, const Config &config,
1001 const JSONRPCRequest &request) -> UniValue {
1003
1004 const CBlockIndex *pindex{nullptr};
1005 const CoinStatsHashType hash_type{
1006 request.params[0].isNull()
1007 ? CoinStatsHashType::HASH_SERIALIZED
1008 : ParseHashType(request.params[0].get_str())};
1009 bool index_requested =
1010 request.params[2].isNull() || request.params[2].get_bool();
1011
1012 NodeContext &node = EnsureAnyNodeContext(request.context);
1014 Chainstate &active_chainstate = chainman.ActiveChainstate();
1015 active_chainstate.ForceFlushStateToDisk();
1016
1017 CCoinsView *coins_view;
1018 BlockManager *blockman;
1019 {
1020 LOCK(::cs_main);
1021 coins_view = &active_chainstate.CoinsDB();
1022 blockman = &active_chainstate.m_blockman;
1023 pindex = blockman->LookupBlockIndex(coins_view->GetBestBlock());
1024 }
1025
1026 if (!request.params[1].isNull()) {
1027 if (!g_coin_stats_index) {
1029 "Querying specific block heights "
1030 "requires coinstatsindex");
1031 }
1032
1033 if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1035 "hash_serialized hash type cannot be "
1036 "queried for a specific block");
1037 }
1038
1039 pindex = ParseHashOrHeight(request.params[1], chainman);
1040 }
1041
1042 if (index_requested && g_coin_stats_index) {
1043 if (!g_coin_stats_index->BlockUntilSyncedToCurrentChain()) {
1044 const IndexSummary summary{
1045 g_coin_stats_index->GetSummary()};
1046
1047 // If a specific block was requested and the index has
1048 // already synced past that height, we can return the data
1049 // already even though the index is not fully synced yet.
1050 if (pindex->nHeight > summary.best_block_height) {
1051 throw JSONRPCError(
1053 strprintf(
1054 "Unable to get data because coinstatsindex is "
1055 "still syncing. Current height: %d",
1056 summary.best_block_height));
1057 }
1058 }
1059 }
1060
1061 const std::optional<CCoinsStats> maybe_stats = GetUTXOStats(
1062 coins_view, *blockman, hash_type, node.rpc_interruption_point,
1063 pindex, index_requested);
1064 if (maybe_stats.has_value()) {
1065 const CCoinsStats &stats = maybe_stats.value();
1066 ret.pushKV("height", int64_t(stats.nHeight));
1067 ret.pushKV("bestblock", stats.hashBlock.GetHex());
1068 ret.pushKV("txouts", int64_t(stats.nTransactionOutputs));
1069 ret.pushKV("bogosize", int64_t(stats.nBogoSize));
1070 if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1071 ret.pushKV("hash_serialized",
1072 stats.hashSerialized.GetHex());
1073 }
1074 if (hash_type == CoinStatsHashType::MUHASH) {
1075 ret.pushKV("muhash", stats.hashSerialized.GetHex());
1076 }
1077 ret.pushKV("total_amount", stats.nTotalAmount);
1078 if (!stats.index_used) {
1079 ret.pushKV("transactions",
1080 static_cast<int64_t>(stats.nTransactions));
1081 ret.pushKV("disk_size", stats.nDiskSize);
1082 } else {
1083 ret.pushKV("total_unspendable_amount",
1085
1086 CCoinsStats prev_stats{};
1087 if (pindex->nHeight > 0) {
1088 const std::optional<CCoinsStats> maybe_prev_stats =
1089 GetUTXOStats(coins_view, *blockman, hash_type,
1090 node.rpc_interruption_point,
1091 pindex->pprev, index_requested);
1092 if (!maybe_prev_stats) {
1094 "Unable to read UTXO set");
1095 }
1096 prev_stats = maybe_prev_stats.value();
1097 }
1098
1099 UniValue block_info(UniValue::VOBJ);
1100 block_info.pushKV(
1101 "prevout_spent",
1103 prev_stats.total_prevout_spent_amount);
1104 block_info.pushKV("coinbase",
1105 stats.total_coinbase_amount -
1106 prev_stats.total_coinbase_amount);
1107 block_info.pushKV(
1108 "new_outputs_ex_coinbase",
1110 prev_stats.total_new_outputs_ex_coinbase_amount);
1111 block_info.pushKV("unspendable",
1113 prev_stats.total_unspendable_amount);
1114
1115 UniValue unspendables(UniValue::VOBJ);
1116 unspendables.pushKV(
1117 "genesis_block",
1119 prev_stats.total_unspendables_genesis_block);
1120 unspendables.pushKV(
1121 "bip30", stats.total_unspendables_bip30 -
1122 prev_stats.total_unspendables_bip30);
1123 unspendables.pushKV(
1124 "scripts", stats.total_unspendables_scripts -
1125 prev_stats.total_unspendables_scripts);
1126 unspendables.pushKV(
1127 "unclaimed_rewards",
1129 prev_stats.total_unspendables_unclaimed_rewards);
1130 block_info.pushKV("unspendables", unspendables);
1131
1132 ret.pushKV("block_info", block_info);
1133 }
1134 } else {
1136 "Unable to read UTXO set");
1137 }
1138 return ret;
1139 },
1140 };
1141}
1142
1144 return RPCHelpMan{
1145 "gettxout",
1146 "Returns details about an unspent transaction output.\n",
1147 {
1149 "The transaction id"},
1150 {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
1151 {"include_mempool", RPCArg::Type::BOOL, RPCArg::Default{true},
1152 "Whether to include the mempool. Note that an unspent output that "
1153 "is spent in the mempool won't appear."},
1154 },
1155 {
1156 RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "",
1157 ""},
1158 RPCResult{
1159 "Otherwise",
1161 "",
1162 "",
1163 {
1164 {RPCResult::Type::STR_HEX, "bestblock",
1165 "The hash of the block at the tip of the chain"},
1166 {RPCResult::Type::NUM, "confirmations",
1167 "The number of confirmations"},
1169 "The transaction value in " + Currency::get().ticker},
1171 "scriptPubKey",
1172 "",
1173 {
1174 {RPCResult::Type::STR_HEX, "asm", ""},
1175 {RPCResult::Type::STR_HEX, "hex", ""},
1176 {RPCResult::Type::NUM, "reqSigs",
1177 "Number of required signatures"},
1178 {RPCResult::Type::STR_HEX, "type",
1179 "The type, eg pubkeyhash"},
1181 "addresses",
1182 "array of eCash addresses",
1183 {{RPCResult::Type::STR, "address", "eCash address"}}},
1184 }},
1185 {RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
1186 }},
1187 },
1188 RPCExamples{"\nGet unspent transactions\n" +
1189 HelpExampleCli("listunspent", "") + "\nView the details\n" +
1190 HelpExampleCli("gettxout", "\"txid\" 1") +
1191 "\nAs a JSON-RPC call\n" +
1192 HelpExampleRpc("gettxout", "\"txid\", 1")},
1193 [&](const RPCHelpMan &self, const Config &config,
1194 const JSONRPCRequest &request) -> UniValue {
1195 NodeContext &node = EnsureAnyNodeContext(request.context);
1197 LOCK(cs_main);
1198
1200
1201 TxId txid(ParseHashV(request.params[0], "txid"));
1202 int n = request.params[1].getInt<int>();
1203 COutPoint out(txid, n);
1204 bool fMempool = true;
1205 if (!request.params[2].isNull()) {
1206 fMempool = request.params[2].get_bool();
1207 }
1208
1209 Coin coin;
1210 Chainstate &active_chainstate = chainman.ActiveChainstate();
1211 CCoinsViewCache *coins_view = &active_chainstate.CoinsTip();
1212
1213 if (fMempool) {
1214 const CTxMemPool &mempool = EnsureMemPool(node);
1215 LOCK(mempool.cs);
1216 CCoinsViewMemPool view(coins_view, mempool);
1217 if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
1218 return NullUniValue;
1219 }
1220 } else {
1221 if (!coins_view->GetCoin(out, coin)) {
1222 return NullUniValue;
1223 }
1224 }
1225
1226 const CBlockIndex *pindex =
1227 active_chainstate.m_blockman.LookupBlockIndex(
1228 coins_view->GetBestBlock());
1229 ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
1230 if (coin.GetHeight() == MEMPOOL_HEIGHT) {
1231 ret.pushKV("confirmations", 0);
1232 } else {
1233 ret.pushKV("confirmations",
1234 int64_t(pindex->nHeight - coin.GetHeight() + 1));
1235 }
1236 ret.pushKV("value", coin.GetTxOut().nValue);
1238 ScriptPubKeyToUniv(coin.GetTxOut().scriptPubKey, o, true);
1239 ret.pushKV("scriptPubKey", o);
1240 ret.pushKV("coinbase", coin.IsCoinBase());
1241
1242 return ret;
1243 },
1244 };
1245}
1246
1248 return RPCHelpMan{
1249 "verifychain",
1250 "Verifies blockchain database.\n",
1251 {
1252 {"checklevel", RPCArg::Type::NUM,
1254 strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL)},
1255 strprintf("How thorough the block verification is:\n - %s",
1256 Join(CHECKLEVEL_DOC, "\n- "))},
1257 {"nblocks", RPCArg::Type::NUM,
1259 "The number of blocks to check."},
1260 },
1262 "Verification finished successfully. If false, check "
1263 "debug.log for reason."},
1264 RPCExamples{HelpExampleCli("verifychain", "") +
1265 HelpExampleRpc("verifychain", "")},
1266 [&](const RPCHelpMan &self, const Config &config,
1267 const JSONRPCRequest &request) -> UniValue {
1268 const int check_level{request.params[0].isNull()
1270 : request.params[0].getInt<int>()};
1271 const int check_depth{request.params[1].isNull()
1273 : request.params[1].getInt<int>()};
1274
1275 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1276 LOCK(cs_main);
1277
1278 Chainstate &active_chainstate = chainman.ActiveChainstate();
1279 return CVerifyDB(chainman.GetNotifications())
1280 .VerifyDB(active_chainstate,
1281 active_chainstate.CoinsTip(), check_level,
1282 check_depth) == VerifyDBResult::SUCCESS;
1283 },
1284 };
1285}
1286
1288 return RPCHelpMan{
1289 "getblockchaininfo",
1290 "Returns an object containing various state info regarding blockchain "
1291 "processing.\n",
1292 {},
1293 RPCResult{
1295 "",
1296 "",
1297 {
1298 {RPCResult::Type::STR, "chain",
1299 "current network name (main, test, regtest)"},
1300 {RPCResult::Type::NUM, "blocks",
1301 "the height of the most-work fully-validated chain. The "
1302 "genesis block has height 0"},
1303 {RPCResult::Type::NUM, "headers",
1304 "the current number of headers we have validated"},
1305 {RPCResult::Type::STR, "bestblockhash",
1306 "the hash of the currently best block"},
1307 {RPCResult::Type::NUM, "difficulty", "the current difficulty"},
1309 "The block time expressed in " + UNIX_EPOCH_TIME},
1310 {RPCResult::Type::NUM_TIME, "mediantime",
1311 "The median block time expressed in " + UNIX_EPOCH_TIME},
1312 {RPCResult::Type::NUM, "verificationprogress",
1313 "estimate of verification progress [0..1]"},
1314 {RPCResult::Type::BOOL, "initialblockdownload",
1315 "(debug information) estimate of whether this node is in "
1316 "Initial Block Download mode"},
1317 {RPCResult::Type::STR_HEX, "chainwork",
1318 "total amount of work in active chain, in hexadecimal"},
1319 {RPCResult::Type::NUM, "size_on_disk",
1320 "the estimated size of the block and undo files on disk"},
1321 {RPCResult::Type::BOOL, "pruned",
1322 "if the blocks are subject to pruning"},
1323 {RPCResult::Type::NUM, "pruneheight",
1324 "lowest-height complete block stored (only present if pruning "
1325 "is enabled)"},
1326 {RPCResult::Type::BOOL, "automatic_pruning",
1327 "whether automatic pruning is enabled (only present if "
1328 "pruning is enabled)"},
1329 {RPCResult::Type::NUM, "prune_target_size",
1330 "the target size used by pruning (only present if automatic "
1331 "pruning is enabled)"},
1332 {RPCResult::Type::STR, "warnings",
1333 "any network and blockchain warnings"},
1334 }},
1335 RPCExamples{HelpExampleCli("getblockchaininfo", "") +
1336 HelpExampleRpc("getblockchaininfo", "")},
1337 [&](const RPCHelpMan &self, const Config &config,
1338 const JSONRPCRequest &request) -> UniValue {
1339 const CChainParams &chainparams = config.GetChainParams();
1340
1341 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1342 LOCK(cs_main);
1343 Chainstate &active_chainstate = chainman.ActiveChainstate();
1344
1345 const CBlockIndex &tip{
1346 *CHECK_NONFATAL(active_chainstate.m_chain.Tip())};
1347 const int height{tip.nHeight};
1348
1350 obj.pushKV("chain", chainparams.NetworkIDString());
1351 obj.pushKV("blocks", height);
1352 obj.pushKV("headers", chainman.m_best_header
1353 ? chainman.m_best_header->nHeight
1354 : -1);
1355 obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex());
1356 obj.pushKV("difficulty", GetDifficulty(&tip));
1357 obj.pushKV("time", tip.GetBlockTime());
1358 obj.pushKV("mediantime", tip.GetMedianTimePast());
1359 obj.pushKV(
1360 "verificationprogress",
1361 GuessVerificationProgress(chainman.GetParams().TxData(), &tip));
1362 obj.pushKV("initialblockdownload",
1363 chainman.IsInitialBlockDownload());
1364 obj.pushKV("chainwork", tip.nChainWork.GetHex());
1365 obj.pushKV("size_on_disk",
1367 obj.pushKV("pruned", chainman.m_blockman.IsPruneMode());
1368
1369 if (chainman.m_blockman.IsPruneMode()) {
1370 bool has_tip_data = tip.nStatus.hasData();
1371 obj.pushKV(
1372 "pruneheight",
1373 has_tip_data
1374 ? chainman.m_blockman.GetFirstStoredBlock(tip)->nHeight
1375 : tip.nHeight + 1);
1376
1377 const bool automatic_pruning{
1378 chainman.m_blockman.GetPruneTarget() !=
1379 BlockManager::PRUNE_TARGET_MANUAL};
1380 obj.pushKV("automatic_pruning", automatic_pruning);
1381 if (automatic_pruning) {
1382 obj.pushKV("prune_target_size",
1383 chainman.m_blockman.GetPruneTarget());
1384 }
1385 }
1386
1387 obj.pushKV("warnings", GetWarnings(false).original);
1388 return obj;
1389 },
1390 };
1391}
1392
1395 bool operator()(const CBlockIndex *a, const CBlockIndex *b) const {
1396 // Make sure that unequal blocks with the same height do not compare
1397 // equal. Use the pointers themselves to make a distinction.
1398 if (a->nHeight != b->nHeight) {
1399 return (a->nHeight > b->nHeight);
1400 }
1401
1402 return a < b;
1403 }
1404};
1405
1407 return RPCHelpMan{
1408 "getchaintips",
1409 "Return information about all known tips in the block tree, including "
1410 "the main chain as well as orphaned branches.\n",
1411 {},
1412 RPCResult{
1414 "",
1415 "",
1417 "",
1418 "",
1419 {
1420 {RPCResult::Type::NUM, "height", "height of the chain tip"},
1421 {RPCResult::Type::STR_HEX, "hash", "block hash of the tip"},
1422 {RPCResult::Type::NUM, "branchlen",
1423 "zero for main chain, otherwise length of branch connecting "
1424 "the tip to the main chain"},
1425 {RPCResult::Type::STR, "status",
1426 "status of the chain, \"active\" for the main chain\n"
1427 "Possible values for status:\n"
1428 "1. \"invalid\" This branch contains at "
1429 "least one invalid block\n"
1430 "2. \"parked\" This branch contains at "
1431 "least one parked block\n"
1432 "3. \"headers-only\" Not all blocks for this "
1433 "branch are available, but the headers are valid\n"
1434 "4. \"valid-headers\" All blocks are available for "
1435 "this branch, but they were never fully validated\n"
1436 "5. \"valid-fork\" This branch is not part of "
1437 "the active chain, but is fully validated\n"
1438 "6. \"active\" This is the tip of the "
1439 "active main chain, which is certainly valid"},
1440 }}}},
1441 RPCExamples{HelpExampleCli("getchaintips", "") +
1442 HelpExampleRpc("getchaintips", "")},
1443 [&](const RPCHelpMan &self, const Config &config,
1444 const JSONRPCRequest &request) -> UniValue {
1445 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1446 LOCK(cs_main);
1447 CChain &active_chain = chainman.ActiveChain();
1448
1460 std::set<const CBlockIndex *, CompareBlocksByHeight> setTips;
1461 std::set<const CBlockIndex *> setOrphans;
1462 std::set<const CBlockIndex *> setPrevs;
1463
1464 for (const auto &[_, block_index] : chainman.BlockIndex()) {
1465 if (!active_chain.Contains(&block_index)) {
1466 setOrphans.insert(&block_index);
1467 setPrevs.insert(block_index.pprev);
1468 }
1469 }
1470
1471 for (std::set<const CBlockIndex *>::iterator it =
1472 setOrphans.begin();
1473 it != setOrphans.end(); ++it) {
1474 if (setPrevs.erase(*it) == 0) {
1475 setTips.insert(*it);
1476 }
1477 }
1478
1479 // Always report the currently active tip.
1480 setTips.insert(active_chain.Tip());
1481
1482 /* Construct the output array. */
1484 for (const CBlockIndex *block : setTips) {
1486 obj.pushKV("height", block->nHeight);
1487 obj.pushKV("hash", block->phashBlock->GetHex());
1488
1489 const int branchLen =
1490 block->nHeight - active_chain.FindFork(block)->nHeight;
1491 obj.pushKV("branchlen", branchLen);
1492
1493 std::string status;
1494 if (active_chain.Contains(block)) {
1495 // This block is part of the currently active chain.
1496 status = "active";
1497 } else if (block->nStatus.isInvalid()) {
1498 // This block or one of its ancestors is invalid.
1499 status = "invalid";
1500 } else if (block->nStatus.isOnParkedChain()) {
1501 // This block or one of its ancestors is parked.
1502 status = "parked";
1503 } else if (!block->HaveNumChainTxs()) {
1504 // This block cannot be connected because full block data
1505 // for it or one of its parents is missing.
1506 status = "headers-only";
1507 } else if (block->IsValid(BlockValidity::SCRIPTS)) {
1508 // This block is fully validated, but no longer part of the
1509 // active chain. It was probably the active block once, but
1510 // was reorganized.
1511 status = "valid-fork";
1512 } else if (block->IsValid(BlockValidity::TREE)) {
1513 // The headers for this block are valid, but it has not been
1514 // validated. It was probably never part of the most-work
1515 // chain.
1516 status = "valid-headers";
1517 } else {
1518 // No clue.
1519 status = "unknown";
1520 }
1521 obj.pushKV("status", status);
1522
1523 res.push_back(obj);
1524 }
1525
1526 return res;
1527 },
1528 };
1529}
1530
1532 return RPCHelpMan{
1533 "preciousblock",
1534 "Treats a block as if it were received before others with the same "
1535 "work.\n"
1536 "\nA later preciousblock call can override the effect of an earlier "
1537 "one.\n"
1538 "\nThe effects of preciousblock are not retained across restarts.\n",
1539 {
1541 "the hash of the block to mark as precious"},
1542 },
1544 RPCExamples{HelpExampleCli("preciousblock", "\"blockhash\"") +
1545 HelpExampleRpc("preciousblock", "\"blockhash\"")},
1546 [&](const RPCHelpMan &self, const Config &config,
1547 const JSONRPCRequest &request) -> UniValue {
1548 BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1549 CBlockIndex *pblockindex;
1550
1551 NodeContext &node = EnsureAnyNodeContext(request.context);
1553 {
1554 LOCK(cs_main);
1555 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1556 if (!pblockindex) {
1558 "Block not found");
1559 }
1560 }
1561
1563 chainman.ActiveChainstate().PreciousBlock(state, pblockindex,
1564 node.avalanche.get());
1565
1566 if (!state.IsValid()) {
1568 }
1569
1570 // Block to make sure wallet/indexers sync before returning
1572
1573 return NullUniValue;
1574 },
1575 };
1576}
1577
1579 return RPCHelpMan{
1580 "invalidateblock",
1581 "Permanently marks a block as invalid, as if it violated a consensus "
1582 "rule.\n",
1583 {
1585 "the hash of the block to mark as invalid"},
1586 },
1588 RPCExamples{HelpExampleCli("invalidateblock", "\"blockhash\"") +
1589 HelpExampleRpc("invalidateblock", "\"blockhash\"")},
1590 [&](const RPCHelpMan &self, const Config &config,
1591 const JSONRPCRequest &request) -> UniValue {
1592 const BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1594
1595 NodeContext &node = EnsureAnyNodeContext(request.context);
1597 CBlockIndex *pblockindex;
1598 {
1599 LOCK(cs_main);
1600 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1601 if (!pblockindex) {
1603 "Block not found");
1604 }
1605 }
1606 chainman.ActiveChainstate().InvalidateBlock(state, pblockindex);
1607
1608 if (state.IsValid()) {
1609 chainman.ActiveChainstate().ActivateBestChain(
1610 state, /*pblock=*/nullptr, node.avalanche.get());
1611 }
1612
1613 if (!state.IsValid()) {
1615 }
1616
1617 // Block to make sure wallet/indexers sync before returning
1619
1620 return NullUniValue;
1621 },
1622 };
1623}
1624
1626 return RPCHelpMan{
1627 "parkblock",
1628 "Marks a block as parked.\n",
1629 {
1631 "the hash of the block to park"},
1632 },
1634 RPCExamples{HelpExampleCli("parkblock", "\"blockhash\"") +
1635 HelpExampleRpc("parkblock", "\"blockhash\"")},
1636 [&](const RPCHelpMan &self, const Config &config,
1637 const JSONRPCRequest &request) -> UniValue {
1638 const std::string strHash = request.params[0].get_str();
1639 const BlockHash hash(uint256S(strHash));
1641
1642 NodeContext &node = EnsureAnyNodeContext(request.context);
1644 Chainstate &active_chainstate = chainman.ActiveChainstate();
1645 CBlockIndex *pblockindex = nullptr;
1646 {
1647 LOCK(cs_main);
1648 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1649 if (!pblockindex) {
1651 "Block not found");
1652 }
1653
1654 if (active_chainstate.IsBlockAvalancheFinalized(pblockindex)) {
1655 // Reset avalanche finalization if we park a finalized
1656 // block.
1657 active_chainstate.ClearAvalancheFinalizedBlock();
1658 }
1659 }
1660
1661 active_chainstate.ParkBlock(state, pblockindex);
1662
1663 if (state.IsValid()) {
1664 active_chainstate.ActivateBestChain(state, /*pblock=*/nullptr,
1665 node.avalanche.get());
1666 }
1667
1668 if (!state.IsValid()) {
1670 }
1671
1672 // Block to make sure wallet/indexers sync before returning
1674
1675 return NullUniValue;
1676 },
1677 };
1678}
1679
1681 return RPCHelpMan{
1682 "reconsiderblock",
1683 "Removes invalidity status of a block, its ancestors and its"
1684 "descendants, reconsider them for activation.\n"
1685 "This can be used to undo the effects of invalidateblock.\n",
1686 {
1688 "the hash of the block to reconsider"},
1689 },
1691 RPCExamples{HelpExampleCli("reconsiderblock", "\"blockhash\"") +
1692 HelpExampleRpc("reconsiderblock", "\"blockhash\"")},
1693 [&](const RPCHelpMan &self, const Config &config,
1694 const JSONRPCRequest &request) -> UniValue {
1695 NodeContext &node = EnsureAnyNodeContext(request.context);
1697 const BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1698
1699 {
1700 LOCK(cs_main);
1701 CBlockIndex *pblockindex =
1702 chainman.m_blockman.LookupBlockIndex(hash);
1703 if (!pblockindex) {
1705 "Block not found");
1706 }
1707
1708 chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex);
1709 }
1710
1712 chainman.ActiveChainstate().ActivateBestChain(
1713 state, /*pblock=*/nullptr, node.avalanche.get());
1714
1715 if (!state.IsValid()) {
1717 }
1718
1719 // Block to make sure wallet/indexers sync before returning
1721
1722 return NullUniValue;
1723 },
1724 };
1725}
1726
1728 return RPCHelpMan{
1729 "unparkblock",
1730 "Removes parked status of a block and its descendants, reconsider "
1731 "them for activation.\n"
1732 "This can be used to undo the effects of parkblock.\n",
1733 {
1735 "the hash of the block to unpark"},
1736 },
1738 RPCExamples{HelpExampleCli("unparkblock", "\"blockhash\"") +
1739 HelpExampleRpc("unparkblock", "\"blockhash\"")},
1740 [&](const RPCHelpMan &self, const Config &config,
1741 const JSONRPCRequest &request) -> UniValue {
1742 const std::string strHash = request.params[0].get_str();
1743 NodeContext &node = EnsureAnyNodeContext(request.context);
1745 const BlockHash hash(uint256S(strHash));
1746 Chainstate &active_chainstate = chainman.ActiveChainstate();
1747
1748 {
1749 LOCK(cs_main);
1750
1751 CBlockIndex *pblockindex =
1752 chainman.m_blockman.LookupBlockIndex(hash);
1753 if (!pblockindex) {
1755 "Block not found");
1756 }
1757
1758 if (!pblockindex->nStatus.isOnParkedChain()) {
1759 // Block to unpark is not parked so there is nothing to do.
1760 return NullUniValue;
1761 }
1762
1763 const CBlockIndex *tip = active_chainstate.m_chain.Tip();
1764 if (tip) {
1765 const CBlockIndex *ancestor =
1766 LastCommonAncestor(tip, pblockindex);
1767 if (active_chainstate.IsBlockAvalancheFinalized(ancestor)) {
1768 // Only reset avalanche finalization if we unpark a
1769 // block that might conflict with avalanche finalized
1770 // blocks.
1771 active_chainstate.ClearAvalancheFinalizedBlock();
1772 }
1773 }
1774
1775 active_chainstate.UnparkBlockAndChildren(pblockindex);
1776 }
1777
1779 active_chainstate.ActivateBestChain(state, /*pblock=*/nullptr,
1780 node.avalanche.get());
1781
1782 if (!state.IsValid()) {
1784 }
1785
1786 // Block to make sure wallet/indexers sync before returning
1788
1789 return NullUniValue;
1790 },
1791 };
1792}
1793
1795 return RPCHelpMan{
1796 "getchaintxstats",
1797 "Compute statistics about the total number and rate of transactions "
1798 "in the chain.\n",
1799 {
1800 {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{"one month"},
1801 "Size of the window in number of blocks"},
1802 {"blockhash", RPCArg::Type::STR_HEX,
1803 RPCArg::DefaultHint{"chain tip"},
1804 "The hash of the block that ends the window."},
1805 },
1807 "",
1808 "",
1809 {
1811 "The timestamp for the final block in the window, "
1812 "expressed in " +
1814 {RPCResult::Type::NUM, "txcount",
1815 "The total number of transactions in the chain up to "
1816 "that point"},
1817 {RPCResult::Type::STR_HEX, "window_final_block_hash",
1818 "The hash of the final block in the window"},
1819 {RPCResult::Type::NUM, "window_final_block_height",
1820 "The height of the final block in the window."},
1821 {RPCResult::Type::NUM, "window_block_count",
1822 "Size of the window in number of blocks"},
1823 {RPCResult::Type::NUM, "window_tx_count",
1824 "The number of transactions in the window. Only "
1825 "returned if \"window_block_count\" is > 0"},
1826 {RPCResult::Type::NUM, "window_interval",
1827 "The elapsed time in the window in seconds. Only "
1828 "returned if \"window_block_count\" is > 0"},
1829 {RPCResult::Type::NUM, "txrate",
1830 "The average rate of transactions per second in the "
1831 "window. Only returned if \"window_interval\" is > 0"},
1832 }},
1833 RPCExamples{HelpExampleCli("getchaintxstats", "") +
1834 HelpExampleRpc("getchaintxstats", "2016")},
1835 [&](const RPCHelpMan &self, const Config &config,
1836 const JSONRPCRequest &request) -> UniValue {
1837 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1838 const CBlockIndex *pindex;
1839
1840 // By default: 1 month
1841 int blockcount =
1842 30 * 24 * 60 * 60 /
1843 config.GetChainParams().GetConsensus().nPowTargetSpacing;
1844
1845 if (request.params[1].isNull()) {
1846 LOCK(cs_main);
1847 pindex = chainman.ActiveTip();
1848 } else {
1849 BlockHash hash(ParseHashV(request.params[1], "blockhash"));
1850 LOCK(cs_main);
1851 pindex = chainman.m_blockman.LookupBlockIndex(hash);
1852 if (!pindex) {
1854 "Block not found");
1855 }
1856 if (!chainman.ActiveChain().Contains(pindex)) {
1858 "Block is not in main chain");
1859 }
1860 }
1861
1862 CHECK_NONFATAL(pindex != nullptr);
1863
1864 if (request.params[0].isNull()) {
1865 blockcount =
1866 std::max(0, std::min(blockcount, pindex->nHeight - 1));
1867 } else {
1868 blockcount = request.params[0].getInt<int>();
1869
1870 if (blockcount < 0 ||
1871 (blockcount > 0 && blockcount >= pindex->nHeight)) {
1873 "Invalid block count: "
1874 "should be between 0 and "
1875 "the block's height - 1");
1876 }
1877 }
1878
1879 const CBlockIndex &past_block{*CHECK_NONFATAL(
1880 pindex->GetAncestor(pindex->nHeight - blockcount))};
1881 const int64_t nTimeDiff{pindex->GetMedianTimePast() -
1882 past_block.GetMedianTimePast()};
1883 const int nTxDiff =
1884 pindex->GetChainTxCount() - past_block.GetChainTxCount();
1885
1887 ret.pushKV("time", pindex->GetBlockTime());
1888 ret.pushKV("txcount", pindex->GetChainTxCount());
1889 ret.pushKV("window_final_block_hash",
1890 pindex->GetBlockHash().GetHex());
1891 ret.pushKV("window_final_block_height", pindex->nHeight);
1892 ret.pushKV("window_block_count", blockcount);
1893 if (blockcount > 0) {
1894 ret.pushKV("window_tx_count", nTxDiff);
1895 ret.pushKV("window_interval", nTimeDiff);
1896 if (nTimeDiff > 0) {
1897 ret.pushKV("txrate", double(nTxDiff) / nTimeDiff);
1898 }
1899 }
1900
1901 return ret;
1902 },
1903 };
1904}
1905
1906template <typename T>
1907static T CalculateTruncatedMedian(std::vector<T> &scores) {
1908 size_t size = scores.size();
1909 if (size == 0) {
1910 return T();
1911 }
1912
1913 std::sort(scores.begin(), scores.end());
1914 if (size % 2 == 0) {
1915 return (scores[size / 2 - 1] + scores[size / 2]) / 2;
1916 } else {
1917 return scores[size / 2];
1918 }
1919}
1920
1921template <typename T> static inline bool SetHasKeys(const std::set<T> &set) {
1922 return false;
1923}
1924template <typename T, typename Tk, typename... Args>
1925static inline bool SetHasKeys(const std::set<T> &set, const Tk &key,
1926 const Args &...args) {
1927 return (set.count(key) != 0) || SetHasKeys(set, args...);
1928}
1929
1930// outpoint (needed for the utxo index) + nHeight + fCoinBase
1931static constexpr size_t PER_UTXO_OVERHEAD =
1932 sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);
1933
1935 const auto &ticker = Currency::get().ticker;
1936 return RPCHelpMan{
1937 "getblockstats",
1938 "Compute per block statistics for a given window. All amounts are "
1939 "in " +
1940 ticker +
1941 ".\n"
1942 "It won't work for some heights with pruning.\n",
1943 {
1944 {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO,
1945 "The block hash or height of the target block",
1947 .type_str = {"", "string or numeric"}}},
1948 {"stats",
1950 RPCArg::DefaultHint{"all values"},
1951 "Values to plot (see result below)",
1952 {
1954 "Selected statistic"},
1956 "Selected statistic"},
1957 },
1959 },
1960 RPCResult{
1962 "",
1963 "",
1964 {
1965 {RPCResult::Type::NUM, "avgfee", "Average fee in the block"},
1966 {RPCResult::Type::NUM, "avgfeerate",
1967 "Average feerate (in satoshis per virtual byte)"},
1968 {RPCResult::Type::NUM, "avgtxsize", "Average transaction size"},
1969 {RPCResult::Type::STR_HEX, "blockhash",
1970 "The block hash (to check for potential reorgs)"},
1971 {RPCResult::Type::NUM, "height", "The height of the block"},
1972 {RPCResult::Type::NUM, "ins",
1973 "The number of inputs (excluding coinbase)"},
1974 {RPCResult::Type::NUM, "maxfee", "Maximum fee in the block"},
1975 {RPCResult::Type::NUM, "maxfeerate",
1976 "Maximum feerate (in satoshis per virtual byte)"},
1977 {RPCResult::Type::NUM, "maxtxsize", "Maximum transaction size"},
1978 {RPCResult::Type::NUM, "medianfee",
1979 "Truncated median fee in the block"},
1980 {RPCResult::Type::NUM, "medianfeerate",
1981 "Truncated median feerate (in " + ticker + " per byte)"},
1982 {RPCResult::Type::NUM, "mediantime",
1983 "The block median time past"},
1984 {RPCResult::Type::NUM, "mediantxsize",
1985 "Truncated median transaction size"},
1986 {RPCResult::Type::NUM, "minfee", "Minimum fee in the block"},
1987 {RPCResult::Type::NUM, "minfeerate",
1988 "Minimum feerate (in satoshis per virtual byte)"},
1989 {RPCResult::Type::NUM, "mintxsize", "Minimum transaction size"},
1990 {RPCResult::Type::NUM, "outs", "The number of outputs"},
1991 {RPCResult::Type::NUM, "subsidy", "The block subsidy"},
1992 {RPCResult::Type::NUM, "time", "The block time"},
1993 {RPCResult::Type::NUM, "total_out",
1994 "Total amount in all outputs (excluding coinbase and thus "
1995 "reward [ie subsidy + totalfee])"},
1996 {RPCResult::Type::NUM, "total_size",
1997 "Total size of all non-coinbase transactions"},
1998 {RPCResult::Type::NUM, "totalfee", "The fee total"},
1999 {RPCResult::Type::NUM, "txs",
2000 "The number of transactions (including coinbase)"},
2001 {RPCResult::Type::NUM, "utxo_increase",
2002 "The increase/decrease in the number of unspent outputs"},
2003 {RPCResult::Type::NUM, "utxo_size_inc",
2004 "The increase/decrease in size for the utxo index (not "
2005 "discounting op_return and similar)"},
2006 }},
2009 "getblockstats",
2010 R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
2011 HelpExampleCli("getblockstats",
2012 R"(1000 '["minfeerate","avgfeerate"]')") +
2014 "getblockstats",
2015 R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") +
2016 HelpExampleRpc("getblockstats",
2017 R"(1000, ["minfeerate","avgfeerate"])")},
2018 [&](const RPCHelpMan &self, const Config &config,
2019 const JSONRPCRequest &request) -> UniValue {
2020 ChainstateManager &chainman = EnsureAnyChainman(request.context);
2021 const CBlockIndex &pindex{*CHECK_NONFATAL(
2022 ParseHashOrHeight(request.params[0], chainman))};
2023
2024 std::set<std::string> stats;
2025 if (!request.params[1].isNull()) {
2026 const UniValue stats_univalue = request.params[1].get_array();
2027 for (unsigned int i = 0; i < stats_univalue.size(); i++) {
2028 const std::string stat = stats_univalue[i].get_str();
2029 stats.insert(stat);
2030 }
2031 }
2032
2033 const CBlock &block = GetBlockChecked(chainman.m_blockman, &pindex);
2034 const CBlockUndo &blockUndo =
2035 GetUndoChecked(chainman.m_blockman, &pindex);
2036
2037 // Calculate everything if nothing selected (default)
2038 const bool do_all = stats.size() == 0;
2039 const bool do_mediantxsize =
2040 do_all || stats.count("mediantxsize") != 0;
2041 const bool do_medianfee = do_all || stats.count("medianfee") != 0;
2042 const bool do_medianfeerate =
2043 do_all || stats.count("medianfeerate") != 0;
2044 const bool loop_inputs =
2045 do_all || do_medianfee || do_medianfeerate ||
2046 SetHasKeys(stats, "utxo_size_inc", "totalfee", "avgfee",
2047 "avgfeerate", "minfee", "maxfee", "minfeerate",
2048 "maxfeerate");
2049 const bool loop_outputs =
2050 do_all || loop_inputs || stats.count("total_out");
2051 const bool do_calculate_size =
2052 do_mediantxsize || loop_inputs ||
2053 SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize",
2054 "maxtxsize");
2055
2056 const int64_t blockMaxSize = config.GetMaxBlockSize();
2057 Amount maxfee = Amount::zero();
2058 Amount maxfeerate = Amount::zero();
2059 Amount minfee = MAX_MONEY;
2060 Amount minfeerate = MAX_MONEY;
2061 Amount total_out = Amount::zero();
2062 Amount totalfee = Amount::zero();
2063 int64_t inputs = 0;
2064 int64_t maxtxsize = 0;
2065 int64_t mintxsize = blockMaxSize;
2066 int64_t outputs = 0;
2067 int64_t total_size = 0;
2068 int64_t utxo_size_inc = 0;
2069 std::vector<Amount> fee_array;
2070 std::vector<Amount> feerate_array;
2071 std::vector<int64_t> txsize_array;
2072
2073 for (size_t i = 0; i < block.vtx.size(); ++i) {
2074 const auto &tx = block.vtx.at(i);
2075 outputs += tx->vout.size();
2076 Amount tx_total_out = Amount::zero();
2077 if (loop_outputs) {
2078 for (const CTxOut &out : tx->vout) {
2079 tx_total_out += out.nValue;
2080 utxo_size_inc +=
2083 }
2084 }
2085
2086 if (tx->IsCoinBase()) {
2087 continue;
2088 }
2089
2090 // Don't count coinbase's fake input
2091 inputs += tx->vin.size();
2092 // Don't count coinbase reward
2093 total_out += tx_total_out;
2094
2095 int64_t tx_size = 0;
2096 if (do_calculate_size) {
2097 tx_size = tx->GetTotalSize();
2098 if (do_mediantxsize) {
2099 txsize_array.push_back(tx_size);
2100 }
2101 maxtxsize = std::max(maxtxsize, tx_size);
2102 mintxsize = std::min(mintxsize, tx_size);
2103 total_size += tx_size;
2104 }
2105
2106 if (loop_inputs) {
2107 Amount tx_total_in = Amount::zero();
2108 const auto &txundo = blockUndo.vtxundo.at(i - 1);
2109 for (const Coin &coin : txundo.vprevout) {
2110 const CTxOut &prevoutput = coin.GetTxOut();
2111
2112 tx_total_in += prevoutput.nValue;
2113 utxo_size_inc -=
2114 GetSerializeSize(prevoutput, PROTOCOL_VERSION) +
2116 }
2117
2118 Amount txfee = tx_total_in - tx_total_out;
2119 CHECK_NONFATAL(MoneyRange(txfee));
2120 if (do_medianfee) {
2121 fee_array.push_back(txfee);
2122 }
2123 maxfee = std::max(maxfee, txfee);
2124 minfee = std::min(minfee, txfee);
2125 totalfee += txfee;
2126
2127 Amount feerate = txfee / tx_size;
2128 if (do_medianfeerate) {
2129 feerate_array.push_back(feerate);
2130 }
2131 maxfeerate = std::max(maxfeerate, feerate);
2132 minfeerate = std::min(minfeerate, feerate);
2133 }
2134 }
2135
2136 UniValue ret_all(UniValue::VOBJ);
2137 ret_all.pushKV("avgfee",
2138 block.vtx.size() > 1
2139 ? (totalfee / int((block.vtx.size() - 1)))
2140 : Amount::zero());
2141 ret_all.pushKV("avgfeerate", total_size > 0
2142 ? (totalfee / total_size)
2143 : Amount::zero());
2144 ret_all.pushKV("avgtxsize",
2145 (block.vtx.size() > 1)
2146 ? total_size / (block.vtx.size() - 1)
2147 : 0);
2148 ret_all.pushKV("blockhash", pindex.GetBlockHash().GetHex());
2149 ret_all.pushKV("height", (int64_t)pindex.nHeight);
2150 ret_all.pushKV("ins", inputs);
2151 ret_all.pushKV("maxfee", maxfee);
2152 ret_all.pushKV("maxfeerate", maxfeerate);
2153 ret_all.pushKV("maxtxsize", maxtxsize);
2154 ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
2155 ret_all.pushKV("medianfeerate",
2156 CalculateTruncatedMedian(feerate_array));
2157 ret_all.pushKV("mediantime", pindex.GetMedianTimePast());
2158 ret_all.pushKV("mediantxsize",
2159 CalculateTruncatedMedian(txsize_array));
2160 ret_all.pushKV("minfee",
2161 minfee == MAX_MONEY ? Amount::zero() : minfee);
2162 ret_all.pushKV("minfeerate", minfeerate == MAX_MONEY
2163 ? Amount::zero()
2164 : minfeerate);
2165 ret_all.pushKV("mintxsize",
2166 mintxsize == blockMaxSize ? 0 : mintxsize);
2167 ret_all.pushKV("outs", outputs);
2168 ret_all.pushKV("subsidy", GetBlockSubsidy(pindex.nHeight,
2169 chainman.GetConsensus()));
2170 ret_all.pushKV("time", pindex.GetBlockTime());
2171 ret_all.pushKV("total_out", total_out);
2172 ret_all.pushKV("total_size", total_size);
2173 ret_all.pushKV("totalfee", totalfee);
2174 ret_all.pushKV("txs", (int64_t)block.vtx.size());
2175 ret_all.pushKV("utxo_increase", outputs - inputs);
2176 ret_all.pushKV("utxo_size_inc", utxo_size_inc);
2177
2178 if (do_all) {
2179 return ret_all;
2180 }
2181
2183 for (const std::string &stat : stats) {
2184 const UniValue &value = ret_all[stat];
2185 if (value.isNull()) {
2186 throw JSONRPCError(
2188 strprintf("Invalid selected statistic %s", stat));
2189 }
2190 ret.pushKV(stat, value);
2191 }
2192 return ret;
2193 },
2194 };
2195}
2196
2197namespace {
2199static bool FindScriptPubKey(std::atomic<int> &scan_progress,
2200 const std::atomic<bool> &should_abort,
2201 int64_t &count, CCoinsViewCursor *cursor,
2202 const std::set<CScript> &needles,
2203 std::map<COutPoint, Coin> &out_results,
2204 std::function<void()> &interruption_point) {
2205 scan_progress = 0;
2206 count = 0;
2207 while (cursor->Valid()) {
2208 COutPoint key;
2209 Coin coin;
2210 if (!cursor->GetKey(key) || !cursor->GetValue(coin)) {
2211 return false;
2212 }
2213 if (++count % 8192 == 0) {
2214 interruption_point();
2215 if (should_abort) {
2216 // allow to abort the scan via the abort reference
2217 return false;
2218 }
2219 }
2220 if (count % 256 == 0) {
2221 // update progress reference every 256 item
2222 const TxId &txid = key.GetTxId();
2223 uint32_t high = 0x100 * *txid.begin() + *(txid.begin() + 1);
2224 scan_progress = int(high * 100.0 / 65536.0 + 0.5);
2225 }
2226 if (needles.count(coin.GetTxOut().scriptPubKey)) {
2227 out_results.emplace(key, coin);
2228 }
2229 cursor->Next();
2230 }
2231 scan_progress = 100;
2232 return true;
2233}
2234} // namespace
2235
2237static std::atomic<int> g_scan_progress;
2238static std::atomic<bool> g_scan_in_progress;
2239static std::atomic<bool> g_should_abort_scan;
2241private:
2243
2244public:
2246
2247 bool reserve() {
2249 if (g_scan_in_progress.exchange(true)) {
2250 return false;
2251 }
2252 m_could_reserve = true;
2253 return true;
2254 }
2255
2257 if (m_could_reserve) {
2258 g_scan_in_progress = false;
2259 }
2260 }
2261};
2262
2264 const auto &ticker = Currency::get().ticker;
2265 return RPCHelpMan{
2266 "scantxoutset",
2267 "Scans the unspent transaction output set for entries that match "
2268 "certain output descriptors.\n"
2269 "Examples of output descriptors are:\n"
2270 " addr(<address>) Outputs whose scriptPubKey "
2271 "corresponds to the specified address (does not include P2PK)\n"
2272 " raw(<hex script>) Outputs whose scriptPubKey "
2273 "equals the specified hex scripts\n"
2274 " combo(<pubkey>) P2PK and P2PKH outputs for "
2275 "the given pubkey\n"
2276 " pkh(<pubkey>) P2PKH outputs for the given "
2277 "pubkey\n"
2278 " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for "
2279 "the given threshold and pubkeys\n"
2280 "\nIn the above, <pubkey> either refers to a fixed public key in "
2281 "hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
2282 "or more path elements separated by \"/\", and optionally ending in "
2283 "\"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
2284 "unhardened or hardened child keys.\n"
2285 "In the latter case, a range needs to be specified by below if "
2286 "different from 1000.\n"
2287 "For more information on output descriptors, see the documentation in "
2288 "the doc/descriptors.md file.\n",
2289 {
2291 "The action to execute\n"
2292 " \"start\" for starting a "
2293 "scan\n"
2294 " \"abort\" for aborting the "
2295 "current scan (returns true when abort was successful)\n"
2296 " \"status\" for "
2297 "progress report (in %) of the current scan"},
2298 {"scanobjects",
2301 "Array of scan objects. Required for \"start\" action\n"
2302 " Every scan object is either a "
2303 "string descriptor or an object:",
2304 {
2306 "An output descriptor"},
2307 {
2308 "",
2311 "An object with output descriptor and metadata",
2312 {
2314 "An output descriptor"},
2315 {"range", RPCArg::Type::RANGE, RPCArg::Default{1000},
2316 "The range of HD chain indexes to explore (either "
2317 "end or [begin,end])"},
2318 },
2319 },
2320 },
2321 RPCArgOptions{.oneline_description = "[scanobjects,...]"}},
2322 },
2323 {
2324 RPCResult{"When action=='abort'", RPCResult::Type::BOOL, "", ""},
2325 RPCResult{"When action=='status' and no scan is in progress",
2326 RPCResult::Type::NONE, "", ""},
2327 RPCResult{
2328 "When action=='status' and scan is in progress",
2330 "",
2331 "",
2332 {
2333 {RPCResult::Type::NUM, "progress", "The scan progress"},
2334 }},
2335 RPCResult{
2336 "When action=='start'",
2338 "",
2339 "",
2340 {
2341 {RPCResult::Type::BOOL, "success",
2342 "Whether the scan was completed"},
2343 {RPCResult::Type::NUM, "txouts",
2344 "The number of unspent transaction outputs scanned"},
2345 {RPCResult::Type::NUM, "height",
2346 "The current block height (index)"},
2347 {RPCResult::Type::STR_HEX, "bestblock",
2348 "The hash of the block at the tip of the chain"},
2350 "unspents",
2351 "",
2352 {
2354 "",
2355 "",
2356 {
2357 {RPCResult::Type::STR_HEX, "txid",
2358 "The transaction id"},
2359 {RPCResult::Type::NUM, "vout", "The vout value"},
2360 {RPCResult::Type::STR_HEX, "scriptPubKey",
2361 "The script key"},
2362 {RPCResult::Type::STR, "desc",
2363 "A specialized descriptor for the matched "
2364 "scriptPubKey"},
2365 {RPCResult::Type::STR_AMOUNT, "amount",
2366 "The total amount in " + ticker +
2367 " of the unspent output"},
2368 {RPCResult::Type::BOOL, "coinbase",
2369 "Whether this is a coinbase output"},
2370 {RPCResult::Type::NUM, "height",
2371 "Height of the unspent transaction output"},
2372 }},
2373 }},
2374 {RPCResult::Type::STR_AMOUNT, "total_amount",
2375 "The total amount of all found unspent outputs in " +
2376 ticker},
2377 }},
2378 },
2379 RPCExamples{""},
2380 [&](const RPCHelpMan &self, const Config &config,
2381 const JSONRPCRequest &request) -> UniValue {
2382 UniValue result(UniValue::VOBJ);
2383 if (request.params[0].get_str() == "status") {
2384 CoinsViewScanReserver reserver;
2385 if (reserver.reserve()) {
2386 // no scan in progress
2387 return NullUniValue;
2388 }
2389 result.pushKV("progress", g_scan_progress.load());
2390 return result;
2391 } else if (request.params[0].get_str() == "abort") {
2392 CoinsViewScanReserver reserver;
2393 if (reserver.reserve()) {
2394 // reserve was possible which means no scan was running
2395 return false;
2396 }
2397 // set the abort flag
2398 g_should_abort_scan = true;
2399 return true;
2400 } else if (request.params[0].get_str() == "start") {
2401 CoinsViewScanReserver reserver;
2402 if (!reserver.reserve()) {
2404 "Scan already in progress, use action "
2405 "\"abort\" or \"status\"");
2406 }
2407
2408 if (request.params.size() < 2) {
2410 "scanobjects argument is required for "
2411 "the start action");
2412 }
2413
2414 std::set<CScript> needles;
2415 std::map<CScript, std::string> descriptors;
2416 Amount total_in = Amount::zero();
2417
2418 // loop through the scan objects
2419 for (const UniValue &scanobject :
2420 request.params[1].get_array().getValues()) {
2421 FlatSigningProvider provider;
2422 auto scripts =
2423 EvalDescriptorStringOrObject(scanobject, provider);
2424 for (CScript &script : scripts) {
2425 std::string inferred =
2426 InferDescriptor(script, provider)->ToString();
2427 needles.emplace(script);
2428 descriptors.emplace(std::move(script),
2429 std::move(inferred));
2430 }
2431 }
2432
2433 // Scan the unspent transaction output set for inputs
2434 UniValue unspents(UniValue::VARR);
2435 std::vector<CTxOut> input_txos;
2436 std::map<COutPoint, Coin> coins;
2437 g_should_abort_scan = false;
2438 g_scan_progress = 0;
2439 int64_t count = 0;
2440 std::unique_ptr<CCoinsViewCursor> pcursor;
2441 const CBlockIndex *tip;
2442 NodeContext &node = EnsureAnyNodeContext(request.context);
2443 {
2445 LOCK(cs_main);
2446 Chainstate &active_chainstate = chainman.ActiveChainstate();
2447 active_chainstate.ForceFlushStateToDisk();
2448 pcursor = CHECK_NONFATAL(std::unique_ptr<CCoinsViewCursor>(
2449 active_chainstate.CoinsDB().Cursor()));
2450 tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
2451 }
2452 bool res = FindScriptPubKey(
2453 g_scan_progress, g_should_abort_scan, count, pcursor.get(),
2454 needles, coins, node.rpc_interruption_point);
2455 result.pushKV("success", res);
2456 result.pushKV("txouts", count);
2457 result.pushKV("height", tip->nHeight);
2458 result.pushKV("bestblock", tip->GetBlockHash().GetHex());
2459
2460 for (const auto &it : coins) {
2461 const COutPoint &outpoint = it.first;
2462 const Coin &coin = it.second;
2463 const CTxOut &txo = coin.GetTxOut();
2464 input_txos.push_back(txo);
2465 total_in += txo.nValue;
2466
2467 UniValue unspent(UniValue::VOBJ);
2468 unspent.pushKV("txid", outpoint.GetTxId().GetHex());
2469 unspent.pushKV("vout", int32_t(outpoint.GetN()));
2470 unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
2471 unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
2472 unspent.pushKV("amount", txo.nValue);
2473 unspent.pushKV("coinbase", coin.IsCoinBase());
2474 unspent.pushKV("height", int32_t(coin.GetHeight()));
2475
2476 unspents.push_back(unspent);
2477 }
2478 result.pushKV("unspents", unspents);
2479 result.pushKV("total_amount", total_in);
2480 } else {
2481 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid command");
2482 }
2483 return result;
2484 },
2485 };
2486}
2487
2489 return RPCHelpMan{
2490 "getblockfilter",
2491 "Retrieve a BIP 157 content filter for a particular block.\n",
2492 {
2494 "The hash of the block"},
2495 {"filtertype", RPCArg::Type::STR, RPCArg::Default{"basic"},
2496 "The type name of the filter"},
2497 },
2499 "",
2500 "",
2501 {
2502 {RPCResult::Type::STR_HEX, "filter",
2503 "the hex-encoded filter data"},
2504 {RPCResult::Type::STR_HEX, "header",
2505 "the hex-encoded filter header"},
2506 }},
2508 HelpExampleCli("getblockfilter",
2509 "\"00000000c937983704a73af28acdec37b049d214a"
2510 "dbda81d7e2a3dd146f6ed09\" \"basic\"") +
2511 HelpExampleRpc("getblockfilter",
2512 "\"00000000c937983704a73af28acdec37b049d214adbda81d7"
2513 "e2a3dd146f6ed09\", \"basic\"")},
2514 [&](const RPCHelpMan &self, const Config &config,
2515 const JSONRPCRequest &request) -> UniValue {
2516 const BlockHash block_hash(
2517 ParseHashV(request.params[0], "blockhash"));
2518 std::string filtertype_name = "basic";
2519 if (!request.params[1].isNull()) {
2520 filtertype_name = request.params[1].get_str();
2521 }
2522
2523 BlockFilterType filtertype;
2524 if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2526 "Unknown filtertype");
2527 }
2528
2529 BlockFilterIndex *index = GetBlockFilterIndex(filtertype);
2530 if (!index) {
2532 "Index is not enabled for filtertype " +
2533 filtertype_name);
2534 }
2535
2536 const CBlockIndex *block_index;
2537 bool block_was_connected;
2538 {
2539 ChainstateManager &chainman =
2540 EnsureAnyChainman(request.context);
2541 LOCK(cs_main);
2542 block_index = chainman.m_blockman.LookupBlockIndex(block_hash);
2543 if (!block_index) {
2545 "Block not found");
2546 }
2547 block_was_connected =
2548 block_index->IsValid(BlockValidity::SCRIPTS);
2549 }
2550
2551 bool index_ready = index->BlockUntilSyncedToCurrentChain();
2552
2553 BlockFilter filter;
2554 uint256 filter_header;
2555 if (!index->LookupFilter(block_index, filter) ||
2556 !index->LookupFilterHeader(block_index, filter_header)) {
2557 int err_code;
2558 std::string errmsg = "Filter not found.";
2559
2560 if (!block_was_connected) {
2561 err_code = RPC_INVALID_ADDRESS_OR_KEY;
2562 errmsg += " Block was not connected to active chain.";
2563 } else if (!index_ready) {
2564 err_code = RPC_MISC_ERROR;
2565 errmsg += " Block filters are still in the process of "
2566 "being indexed.";
2567 } else {
2568 err_code = RPC_INTERNAL_ERROR;
2569 errmsg += " This error is unexpected and indicates index "
2570 "corruption.";
2571 }
2572
2573 throw JSONRPCError(err_code, errmsg);
2574 }
2575
2577 ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
2578 ret.pushKV("header", filter_header.GetHex());
2579 return ret;
2580 },
2581 };
2582}
2583
2590 return RPCHelpMan{
2591 "dumptxoutset",
2592 "Write the serialized UTXO set to disk.\n",
2593 {
2595 "path to the output file. If relative, will be prefixed by "
2596 "datadir."},
2597 },
2599 "",
2600 "",
2601 {
2602 {RPCResult::Type::NUM, "coins_written",
2603 "the number of coins written in the snapshot"},
2604 {RPCResult::Type::STR_HEX, "base_hash",
2605 "the hash of the base of the snapshot"},
2606 {RPCResult::Type::NUM, "base_height",
2607 "the height of the base of the snapshot"},
2608 {RPCResult::Type::STR, "path",
2609 "the absolute path that the snapshot was written to"},
2610 {RPCResult::Type::STR_HEX, "txoutset_hash",
2611 "the hash of the UTXO set contents"},
2612 {RPCResult::Type::NUM, "nchaintx",
2613 "the number of transactions in the chain up to and "
2614 "including the base block"},
2615 }},
2616 RPCExamples{HelpExampleCli("dumptxoutset", "utxo.dat")},
2617 [&](const RPCHelpMan &self, const Config &config,
2618 const JSONRPCRequest &request) -> UniValue {
2619 const ArgsManager &args{EnsureAnyArgsman(request.context)};
2620 const fs::path path = fsbridge::AbsPathJoin(
2621 args.GetDataDirNet(), fs::u8path(request.params[0].get_str()));
2622 // Write to a temporary path and then move into `path` on completion
2623 // to avoid confusion due to an interruption.
2624 const fs::path temppath = fsbridge::AbsPathJoin(
2625 args.GetDataDirNet(),
2626 fs::u8path(request.params[0].get_str() + ".incomplete"));
2627
2628 if (fs::exists(path)) {
2630 path.u8string() +
2631 " already exists. If you are sure this "
2632 "is what you want, "
2633 "move it out of the way first");
2634 }
2635
2636 FILE *file{fsbridge::fopen(temppath, "wb")};
2637 AutoFile afile{file};
2638 NodeContext &node = EnsureAnyNodeContext(request.context);
2640 node, node.chainman->ActiveChainstate(), afile, path, temppath);
2641 fs::rename(temppath, path);
2642
2643 return result;
2644 },
2645 };
2646}
2647
2649 AutoFile &afile, const fs::path &path,
2650 const fs::path &temppath) {
2651 std::unique_ptr<CCoinsViewCursor> pcursor;
2652 std::optional<CCoinsStats> maybe_stats;
2653 const CBlockIndex *tip;
2654
2655 {
2656 // We need to lock cs_main to ensure that the coinsdb isn't
2657 // written to between (i) flushing coins cache to disk
2658 // (coinsdb), (ii) getting stats based upon the coinsdb, and
2659 // (iii) constructing a cursor to the coinsdb for use below this
2660 // block.
2661 //
2662 // Cursors returned by leveldb iterate over snapshots, so the
2663 // contents of the pcursor will not be affected by simultaneous
2664 // writes during use below this block.
2665 //
2666 // See discussion here:
2667 // https://github.com/bitcoin/bitcoin/pull/15606#discussion_r274479369
2668 //
2669 LOCK(::cs_main);
2670
2671 chainstate.ForceFlushStateToDisk();
2672
2673 maybe_stats = GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman,
2674 CoinStatsHashType::HASH_SERIALIZED,
2675 node.rpc_interruption_point);
2676 if (!maybe_stats) {
2677 throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
2678 }
2679
2680 pcursor =
2681 std::unique_ptr<CCoinsViewCursor>(chainstate.CoinsDB().Cursor());
2682 tip = CHECK_NONFATAL(
2683 chainstate.m_blockman.LookupBlockIndex(maybe_stats->hashBlock));
2684 }
2685
2687 strprintf("writing UTXO snapshot at height %s (%s) to file %s (via %s)",
2688 tip->nHeight, tip->GetBlockHash().ToString(),
2689 fs::PathToString(path), fs::PathToString(temppath)));
2690
2691 SnapshotMetadata metadata{tip->GetBlockHash(), maybe_stats->coins_count};
2692
2693 afile << metadata;
2694
2695 COutPoint key;
2696 Coin coin;
2697 unsigned int iter{0};
2698
2699 while (pcursor->Valid()) {
2700 if (iter % 5000 == 0) {
2701 node.rpc_interruption_point();
2702 }
2703 ++iter;
2704 if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
2705 afile << key;
2706 afile << coin;
2707 }
2708
2709 pcursor->Next();
2710 }
2711
2712 afile.fclose();
2713
2714 UniValue result(UniValue::VOBJ);
2715 result.pushKV("coins_written", maybe_stats->coins_count);
2716 result.pushKV("base_hash", tip->GetBlockHash().ToString());
2717 result.pushKV("base_height", tip->nHeight);
2718 result.pushKV("path", path.u8string());
2719 result.pushKV("txoutset_hash", maybe_stats->hashSerialized.ToString());
2720 result.pushKV("nchaintx", tip->nChainTx);
2721 return result;
2722}
2723
2725 // clang-format off
2726 static const CRPCCommand commands[] = {
2727 // category actor (function)
2728 // ------------------ ----------------------
2729 { "blockchain", getbestblockhash, },
2730 { "blockchain", getblock, },
2731 { "blockchain", getblockfrompeer, },
2732 { "blockchain", getblockchaininfo, },
2733 { "blockchain", getblockcount, },
2734 { "blockchain", getblockhash, },
2735 { "blockchain", getblockheader, },
2736 { "blockchain", getblockstats, },
2737 { "blockchain", getchaintips, },
2738 { "blockchain", getchaintxstats, },
2739 { "blockchain", getdifficulty, },
2740 { "blockchain", gettxout, },
2741 { "blockchain", gettxoutsetinfo, },
2742 { "blockchain", pruneblockchain, },
2743 { "blockchain", verifychain, },
2744 { "blockchain", preciousblock, },
2745 { "blockchain", scantxoutset, },
2746 { "blockchain", getblockfilter, },
2747
2748 /* Not shown in help */
2749 { "hidden", invalidateblock, },
2750 { "hidden", parkblock, },
2751 { "hidden", reconsiderblock, },
2752 { "hidden", syncwithvalidationinterfacequeue, },
2753 { "hidden", dumptxoutset, },
2754 { "hidden", unparkblock, },
2755 { "hidden", waitfornewblock, },
2756 { "hidden", waitforblock, },
2757 { "hidden", waitforblockheight, },
2758 };
2759 // clang-format on
2760 for (const auto &c : commands) {
2761 t.appendCommand(c.name, &c);
2762 }
2763}
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
RPCHelpMan gettxout()
static RPCHelpMan getblock()
Definition: blockchain.cpp:677
static int ComputeNextBlockAndDepth(const CBlockIndex *tip, const CBlockIndex *blockindex, const CBlockIndex *&next)
Definition: blockchain.cpp:88
static RPCHelpMan getdifficulty()
Definition: blockchain.cpp:439
static std::atomic< bool > g_scan_in_progress
static bool SetHasKeys(const std::set< T > &set)
static RPCHelpMan reconsiderblock()
static T CalculateTruncatedMedian(std::vector< T > &scores)
static RPCHelpMan invalidateblock()
static RPCHelpMan syncwithvalidationinterfacequeue()
Definition: blockchain.cpp:422
static RPCHelpMan getchaintips()
static RPCHelpMan gettxoutsetinfo()
Definition: blockchain.cpp:908
static RPCHelpMan getblockstats()
static CoinStatsHashType ParseHashType(const std::string &hash_type_input)
Definition: blockchain.cpp:894
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:70
static RPCHelpMan scantxoutset()
static std::condition_variable cond_blockchange
Definition: blockchain.cpp:64
static std::atomic< int > g_scan_progress
RAII object to prevent concurrency issue when scanning the txout set.
static CBlockUndo GetUndoChecked(BlockManager &blockman, const CBlockIndex *pblockindex)
Definition: blockchain.cpp:658
static RPCHelpMan getblockfilter()
static RPCHelpMan getbestblockhash()
Definition: blockchain.cpp:216
static CBlock GetBlockChecked(BlockManager &blockman, const CBlockIndex *pblockindex)
Definition: blockchain.cpp:636
RPCHelpMan getblockchaininfo()
UniValue blockToJSON(BlockManager &blockman, const CBlock &block, const CBlockIndex *tip, const CBlockIndex *blockindex, bool txDetails)
Block description to JSON.
Definition: blockchain.cpp:165
static RPCHelpMan getchaintxstats()
static RPCHelpMan waitforblock()
Definition: blockchain.cpp:300
static RPCHelpMan getblockfrompeer()
Definition: blockchain.cpp:459
static RPCHelpMan getblockhash()
Definition: blockchain.cpp:511
void RegisterBlockchainRPCCommands(CRPCTable &t)
static RPCHelpMan verifychain()
static std::atomic< bool > g_should_abort_scan
RPCHelpMan unparkblock()
UniValue blockheaderToJSON(const CBlockIndex *tip, const CBlockIndex *blockindex)
Block header to JSON.
Definition: blockchain.cpp:131
static RPCHelpMan waitforblockheight()
Definition: blockchain.cpp:362
static const CBlockIndex * ParseHashOrHeight(const UniValue &param, ChainstateManager &chainman)
Definition: blockchain.cpp:99
static RPCHelpMan pruneblockchain()
Definition: blockchain.cpp:816
static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange)
static RPCHelpMan getblockheader()
Definition: blockchain.cpp:540
RPCHelpMan parkblock()
UniValue CreateUTXOSnapshot(NodeContext &node, Chainstate &chainstate, AutoFile &afile, const fs::path &path, const fs::path &temppath)
Helper to create UTXO snapshots given a chainstate and a file handle.
static GlobalMutex cs_blockchange
Definition: blockchain.cpp:63
static RPCHelpMan dumptxoutset()
Serialize the UTXO set to a file for loading elsewhere.
static RPCHelpMan getblockcount()
Definition: blockchain.cpp:198
static RPCHelpMan waitfornewblock()
Definition: blockchain.cpp:243
void RPCNotifyBlockChange(const CBlockIndex *pindex)
Callback for when block tip changed.
Definition: blockchain.cpp:234
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
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:53
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:528
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.
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:210
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
int64_t GetChainTxCount() const
Get the number of transaction in the chain so far.
Definition: blockindex.h:138
uint32_t nTime
Definition: blockindex.h:76
uint32_t nNonce
Definition: blockindex.h:78
int64_t GetBlockTime() const
Definition: blockindex.h:179
int64_t GetMedianTimePast() const
Definition: blockindex.h:191
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:102
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:85
std::string NetworkIDString() const
Return the BIP70 network string (main, test or regtest)
Definition: chainparams.h:132
const ChainTxData & TxData() const
Definition: chainparams.h:152
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:221
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:95
Cursor for iterating over CoinsView state.
Definition: coins.h:143
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:208
Abstract view on the open txout dataset.
Definition: coins.h:163
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:635
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
GetCoin, returning whether it exists and is not spent.
Definition: txmempool.cpp:675
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:177
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:327
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:214
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:310
bool isSpent(const COutPoint &outpoint) const
Definition: txmempool.cpp:135
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:621
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:700
bool IsBlockAvalancheFinalized(const CBlockIndex *pindex) const EXCLUSIVE_LOCKS_REQUIRED(!cs_avalancheFinalizedBlockIndex)
Checks if a block is finalized by avalanche voting.
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:799
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:826
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:833
node::BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all Chainstate instances.
Definition: validation.h:757
void ClearAvalancheFinalizedBlock() EXCLUSIVE_LOCKS_REQUIRED(!cs_avalancheFinalizedBlockIndex)
Clear avalanche finalization.
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:1147
node::BlockMap & BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:1414
SnapshotCompletionResult MaybeCompleteSnapshotValidation(std::function< void(bilingual_str)> shutdown_fnc=[](bilingual_str msg) { AbortNode(msg.original, msg);}) 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:1390
kernel::Notifications & GetNotifications() const
Definition: validation.h:1249
bool IsInitialBlockDownload() const
Check whether we are doing an initial block download (synchronizing from disk or network)
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1397
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1394
const CChainParams & GetParams() const
Definition: validation.h:1234
const Consensus::Params & GetConsensus() const
Definition: validation.h:1237
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1391
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1280
A UTXO entry.
Definition: coins.h:28
uint32_t GetHeight() const
Definition: coins.h:45
bool IsCoinBase() const
Definition: coins.h:46
CTxOut & GetTxOut()
Definition: coins.h:49
Definition: config.h:19
Different type to mark Mutex at global scope.
Definition: sync.h:144
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.
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:74
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:259
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:256
Metadata describing a serialized version of a UTXO set from which an assumeutxo Chainstate can be con...
Definition: utxo_snapshot.h:21
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, int serialize_flags=0, const CTxUndo *txundo=nullptr)
Definition: core_write.cpp:217
void ScriptPubKeyToUniv(const CScript &scriptPubKey, UniValue &out, bool fIncludeHex)
Definition: core_write.cpp:190
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.
#define LogPrint(category,...)
Definition: logging.h:238
unsigned int nHeight
@ RPC
Definition: logging.h:47
@ NONE
Definition: logging.h:39
static path u8path(const std::string &utf8_str)
Definition: fs.h:90
static bool exists(const path &p)
Definition: fs.h:102
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition: fs.h:142
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
int64_t NodeId
Definition: nodeid.h:10
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:315
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_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:150
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:167
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:1290
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:22
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded values (throws error if not hex).
Definition: util.cpp:73
@ SER_NETWORK
Definition: serialize.h:152
size_t GetSerializeSize(const T &t, int nVersion=0)
Definition: serialize.h:1258
bool IsRPCRunning()
Query whether RPC is running.
Definition: server.cpp:378
int RPCSerializationFlags()
Retrieves any serialization flags requested in command line argument.
Definition: server.cpp:679
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 & EnsureAnyArgsman(const std::any &context)
Definition: server_util.cpp:48
auto Join(const std::vector< T > &list, const BaseType &separator, UnaryOp unary_op) -> decltype(unary_op(list.at(0)))
Join a list of items.
Definition: string.h:63
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
BlockHash hash
Definition: blockchain.cpp:59
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.
std::string DefaultHint
Hint for default value.
Definition: util.h:195
@ OMITTED
The arg is optional for one of two reasons:
@ NO
Required arg.
std::string oneline_description
Should be empty unless it is supposed to override the auto-generated summary line.
Definition: util.h:128
bool skip_type_check
Definition: util.h:125
@ 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 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:46
#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:50
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:99
void PruneBlockFilesManual(Chainstate &active_chainstate, int nManualPruneHeight)
Prune block files up to a given height.
static constexpr int DEFAULT_CHECKLEVEL
Definition: validation.h:98
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:96
static const signed int DEFAULT_CHECKBLOCKS
Definition: validation.h:97
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