Bitcoin ABC 0.30.5
P2P Digital Currency
blockchain.cpp
Go to the documentation of this file.
1// Copyright (c) 2010 Satoshi Nakamoto
2// Copyright (c) 2009-2019 The Bitcoin Core developers
3// Distributed under the MIT software license, see the accompanying
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6#include <rpc/blockchain.h>
7
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 const CBlockIndex *last_block{
886 active_chainstate.m_blockman.GetFirstStoredBlock(block)};
887
888 return static_cast<uint64_t>(last_block->nHeight);
889 },
890 };
891}
892
893static CoinStatsHashType ParseHashType(const std::string &hash_type_input) {
894 if (hash_type_input == "hash_serialized") {
895 return CoinStatsHashType::HASH_SERIALIZED;
896 } else if (hash_type_input == "muhash") {
897 return CoinStatsHashType::MUHASH;
898 } else if (hash_type_input == "none") {
900 } else {
901 throw JSONRPCError(
903 strprintf("%s is not a valid hash_type", hash_type_input));
904 }
905}
906
908 return RPCHelpMan{
909 "gettxoutsetinfo",
910 "Returns statistics about the unspent transaction output set.\n"
911 "Note this call may take some time if you are not using "
912 "coinstatsindex.\n",
913 {
914 {"hash_type", RPCArg::Type::STR, RPCArg::Default{"hash_serialized"},
915 "Which UTXO set hash should be calculated. Options: "
916 "'hash_serialized' (the legacy algorithm), 'muhash', 'none'."},
918 "The block hash or height of the target height (only available "
919 "with coinstatsindex).",
921 .type_str = {"", "string or numeric"}}},
922 {"use_index", RPCArg::Type::BOOL, RPCArg::Default{true},
923 "Use coinstatsindex, if available."},
924 },
925 RPCResult{
927 "",
928 "",
929 {
930 {RPCResult::Type::NUM, "height",
931 "The current block height (index)"},
932 {RPCResult::Type::STR_HEX, "bestblock",
933 "The hash of the block at the tip of the chain"},
934 {RPCResult::Type::NUM, "txouts",
935 "The number of unspent transaction outputs"},
936 {RPCResult::Type::NUM, "bogosize",
937 "Database-independent, meaningless metric indicating "
938 "the UTXO set size"},
939 {RPCResult::Type::STR_HEX, "hash_serialized",
940 /* optional */ true,
941 "The serialized hash (only present if 'hash_serialized' "
942 "hash_type is chosen)"},
943 {RPCResult::Type::STR_HEX, "muhash", /* optional */ true,
944 "The serialized hash (only present if 'muhash' "
945 "hash_type is chosen)"},
946 {RPCResult::Type::NUM, "transactions",
947 "The number of transactions with unspent outputs (not "
948 "available when coinstatsindex is used)"},
949 {RPCResult::Type::NUM, "disk_size",
950 "The estimated size of the chainstate on disk (not "
951 "available when coinstatsindex is used)"},
952 {RPCResult::Type::STR_AMOUNT, "total_amount",
953 "The total amount"},
954 {RPCResult::Type::STR_AMOUNT, "total_unspendable_amount",
955 "The total amount of coins permanently excluded from the UTXO "
956 "set (only available if coinstatsindex is used)"},
958 "block_info",
959 "Info on amounts in the block at this block height (only "
960 "available if coinstatsindex is used)",
961 {{RPCResult::Type::STR_AMOUNT, "prevout_spent",
962 "Total amount of all prevouts spent in this block"},
963 {RPCResult::Type::STR_AMOUNT, "coinbase",
964 "Coinbase subsidy amount of this block"},
965 {RPCResult::Type::STR_AMOUNT, "new_outputs_ex_coinbase",
966 "Total amount of new outputs created by this block"},
967 {RPCResult::Type::STR_AMOUNT, "unspendable",
968 "Total amount of unspendable outputs created in this block"},
970 "unspendables",
971 "Detailed view of the unspendable categories",
972 {
973 {RPCResult::Type::STR_AMOUNT, "genesis_block",
974 "The unspendable amount of the Genesis block subsidy"},
976 "Transactions overridden by duplicates (no longer "
977 "possible with BIP30)"},
978 {RPCResult::Type::STR_AMOUNT, "scripts",
979 "Amounts sent to scripts that are unspendable (for "
980 "example OP_RETURN outputs)"},
981 {RPCResult::Type::STR_AMOUNT, "unclaimed_rewards",
982 "Fee rewards that miners did not claim in their "
983 "coinbase transaction"},
984 }}}},
985 }},
987 HelpExampleCli("gettxoutsetinfo", "") +
988 HelpExampleCli("gettxoutsetinfo", R"("none")") +
989 HelpExampleCli("gettxoutsetinfo", R"("none" 1000)") +
991 "gettxoutsetinfo",
992 R"("none" '"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"')") +
993 HelpExampleRpc("gettxoutsetinfo", "") +
994 HelpExampleRpc("gettxoutsetinfo", R"("none")") +
995 HelpExampleRpc("gettxoutsetinfo", R"("none", 1000)") +
997 "gettxoutsetinfo",
998 R"("none", "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09")")},
999 [&](const RPCHelpMan &self, const Config &config,
1000 const JSONRPCRequest &request) -> UniValue {
1002
1003 const CBlockIndex *pindex{nullptr};
1004 const CoinStatsHashType hash_type{
1005 request.params[0].isNull()
1006 ? CoinStatsHashType::HASH_SERIALIZED
1007 : ParseHashType(request.params[0].get_str())};
1008 bool index_requested =
1009 request.params[2].isNull() || request.params[2].get_bool();
1010
1011 NodeContext &node = EnsureAnyNodeContext(request.context);
1013 Chainstate &active_chainstate = chainman.ActiveChainstate();
1014 active_chainstate.ForceFlushStateToDisk();
1015
1016 CCoinsView *coins_view;
1017 BlockManager *blockman;
1018 {
1019 LOCK(::cs_main);
1020 coins_view = &active_chainstate.CoinsDB();
1021 blockman = &active_chainstate.m_blockman;
1022 pindex = blockman->LookupBlockIndex(coins_view->GetBestBlock());
1023 }
1024
1025 if (!request.params[1].isNull()) {
1026 if (!g_coin_stats_index) {
1028 "Querying specific block heights "
1029 "requires coinstatsindex");
1030 }
1031
1032 if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1034 "hash_serialized hash type cannot be "
1035 "queried for a specific block");
1036 }
1037
1038 pindex = ParseHashOrHeight(request.params[1], chainman);
1039 }
1040
1041 if (index_requested && g_coin_stats_index) {
1042 if (!g_coin_stats_index->BlockUntilSyncedToCurrentChain()) {
1043 const IndexSummary summary{
1044 g_coin_stats_index->GetSummary()};
1045
1046 // If a specific block was requested and the index has
1047 // already synced past that height, we can return the data
1048 // already even though the index is not fully synced yet.
1049 if (pindex->nHeight > summary.best_block_height) {
1050 throw JSONRPCError(
1052 strprintf(
1053 "Unable to get data because coinstatsindex is "
1054 "still syncing. Current height: %d",
1055 summary.best_block_height));
1056 }
1057 }
1058 }
1059
1060 const std::optional<CCoinsStats> maybe_stats = GetUTXOStats(
1061 coins_view, *blockman, hash_type, node.rpc_interruption_point,
1062 pindex, index_requested);
1063 if (maybe_stats.has_value()) {
1064 const CCoinsStats &stats = maybe_stats.value();
1065 ret.pushKV("height", int64_t(stats.nHeight));
1066 ret.pushKV("bestblock", stats.hashBlock.GetHex());
1067 ret.pushKV("txouts", int64_t(stats.nTransactionOutputs));
1068 ret.pushKV("bogosize", int64_t(stats.nBogoSize));
1069 if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1070 ret.pushKV("hash_serialized",
1071 stats.hashSerialized.GetHex());
1072 }
1073 if (hash_type == CoinStatsHashType::MUHASH) {
1074 ret.pushKV("muhash", stats.hashSerialized.GetHex());
1075 }
1076 ret.pushKV("total_amount", stats.nTotalAmount);
1077 if (!stats.index_used) {
1078 ret.pushKV("transactions",
1079 static_cast<int64_t>(stats.nTransactions));
1080 ret.pushKV("disk_size", stats.nDiskSize);
1081 } else {
1082 ret.pushKV("total_unspendable_amount",
1084
1085 CCoinsStats prev_stats{};
1086 if (pindex->nHeight > 0) {
1087 const std::optional<CCoinsStats> maybe_prev_stats =
1088 GetUTXOStats(coins_view, *blockman, hash_type,
1089 node.rpc_interruption_point,
1090 pindex->pprev, index_requested);
1091 if (!maybe_prev_stats) {
1093 "Unable to read UTXO set");
1094 }
1095 prev_stats = maybe_prev_stats.value();
1096 }
1097
1098 UniValue block_info(UniValue::VOBJ);
1099 block_info.pushKV(
1100 "prevout_spent",
1102 prev_stats.total_prevout_spent_amount);
1103 block_info.pushKV("coinbase",
1104 stats.total_coinbase_amount -
1105 prev_stats.total_coinbase_amount);
1106 block_info.pushKV(
1107 "new_outputs_ex_coinbase",
1109 prev_stats.total_new_outputs_ex_coinbase_amount);
1110 block_info.pushKV("unspendable",
1112 prev_stats.total_unspendable_amount);
1113
1114 UniValue unspendables(UniValue::VOBJ);
1115 unspendables.pushKV(
1116 "genesis_block",
1118 prev_stats.total_unspendables_genesis_block);
1119 unspendables.pushKV(
1120 "bip30", stats.total_unspendables_bip30 -
1121 prev_stats.total_unspendables_bip30);
1122 unspendables.pushKV(
1123 "scripts", stats.total_unspendables_scripts -
1124 prev_stats.total_unspendables_scripts);
1125 unspendables.pushKV(
1126 "unclaimed_rewards",
1128 prev_stats.total_unspendables_unclaimed_rewards);
1129 block_info.pushKV("unspendables", unspendables);
1130
1131 ret.pushKV("block_info", block_info);
1132 }
1133 } else {
1135 "Unable to read UTXO set");
1136 }
1137 return ret;
1138 },
1139 };
1140}
1141
1143 return RPCHelpMan{
1144 "gettxout",
1145 "Returns details about an unspent transaction output.\n",
1146 {
1148 "The transaction id"},
1149 {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
1150 {"include_mempool", RPCArg::Type::BOOL, RPCArg::Default{true},
1151 "Whether to include the mempool. Note that an unspent output that "
1152 "is spent in the mempool won't appear."},
1153 },
1154 {
1155 RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "",
1156 ""},
1157 RPCResult{
1158 "Otherwise",
1160 "",
1161 "",
1162 {
1163 {RPCResult::Type::STR_HEX, "bestblock",
1164 "The hash of the block at the tip of the chain"},
1165 {RPCResult::Type::NUM, "confirmations",
1166 "The number of confirmations"},
1168 "The transaction value in " + Currency::get().ticker},
1170 "scriptPubKey",
1171 "",
1172 {
1173 {RPCResult::Type::STR_HEX, "asm", ""},
1174 {RPCResult::Type::STR_HEX, "hex", ""},
1175 {RPCResult::Type::NUM, "reqSigs",
1176 "Number of required signatures"},
1177 {RPCResult::Type::STR_HEX, "type",
1178 "The type, eg pubkeyhash"},
1180 "addresses",
1181 "array of eCash addresses",
1182 {{RPCResult::Type::STR, "address", "eCash address"}}},
1183 }},
1184 {RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
1185 }},
1186 },
1187 RPCExamples{"\nGet unspent transactions\n" +
1188 HelpExampleCli("listunspent", "") + "\nView the details\n" +
1189 HelpExampleCli("gettxout", "\"txid\" 1") +
1190 "\nAs a JSON-RPC call\n" +
1191 HelpExampleRpc("gettxout", "\"txid\", 1")},
1192 [&](const RPCHelpMan &self, const Config &config,
1193 const JSONRPCRequest &request) -> UniValue {
1194 NodeContext &node = EnsureAnyNodeContext(request.context);
1196 LOCK(cs_main);
1197
1199
1200 TxId txid(ParseHashV(request.params[0], "txid"));
1201 int n = request.params[1].getInt<int>();
1202 COutPoint out(txid, n);
1203 bool fMempool = true;
1204 if (!request.params[2].isNull()) {
1205 fMempool = request.params[2].get_bool();
1206 }
1207
1208 Coin coin;
1209 Chainstate &active_chainstate = chainman.ActiveChainstate();
1210 CCoinsViewCache *coins_view = &active_chainstate.CoinsTip();
1211
1212 if (fMempool) {
1213 const CTxMemPool &mempool = EnsureMemPool(node);
1214 LOCK(mempool.cs);
1215 CCoinsViewMemPool view(coins_view, mempool);
1216 if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
1217 return NullUniValue;
1218 }
1219 } else {
1220 if (!coins_view->GetCoin(out, coin)) {
1221 return NullUniValue;
1222 }
1223 }
1224
1225 const CBlockIndex *pindex =
1226 active_chainstate.m_blockman.LookupBlockIndex(
1227 coins_view->GetBestBlock());
1228 ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
1229 if (coin.GetHeight() == MEMPOOL_HEIGHT) {
1230 ret.pushKV("confirmations", 0);
1231 } else {
1232 ret.pushKV("confirmations",
1233 int64_t(pindex->nHeight - coin.GetHeight() + 1));
1234 }
1235 ret.pushKV("value", coin.GetTxOut().nValue);
1237 ScriptPubKeyToUniv(coin.GetTxOut().scriptPubKey, o, true);
1238 ret.pushKV("scriptPubKey", o);
1239 ret.pushKV("coinbase", coin.IsCoinBase());
1240
1241 return ret;
1242 },
1243 };
1244}
1245
1247 return RPCHelpMan{
1248 "verifychain",
1249 "Verifies blockchain database.\n",
1250 {
1251 {"checklevel", RPCArg::Type::NUM,
1253 strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL)},
1254 strprintf("How thorough the block verification is:\n - %s",
1255 Join(CHECKLEVEL_DOC, "\n- "))},
1256 {"nblocks", RPCArg::Type::NUM,
1258 "The number of blocks to check."},
1259 },
1261 "Verification finished successfully. If false, check "
1262 "debug.log for reason."},
1263 RPCExamples{HelpExampleCli("verifychain", "") +
1264 HelpExampleRpc("verifychain", "")},
1265 [&](const RPCHelpMan &self, const Config &config,
1266 const JSONRPCRequest &request) -> UniValue {
1267 const int check_level{request.params[0].isNull()
1269 : request.params[0].getInt<int>()};
1270 const int check_depth{request.params[1].isNull()
1272 : request.params[1].getInt<int>()};
1273
1274 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1275 LOCK(cs_main);
1276
1277 Chainstate &active_chainstate = chainman.ActiveChainstate();
1278 return CVerifyDB(chainman.GetNotifications())
1279 .VerifyDB(active_chainstate,
1280 active_chainstate.CoinsTip(), check_level,
1281 check_depth) == VerifyDBResult::SUCCESS;
1282 },
1283 };
1284}
1285
1287 return RPCHelpMan{
1288 "getblockchaininfo",
1289 "Returns an object containing various state info regarding blockchain "
1290 "processing.\n",
1291 {},
1292 RPCResult{
1294 "",
1295 "",
1296 {
1297 {RPCResult::Type::STR, "chain",
1298 "current network name (main, test, regtest)"},
1299 {RPCResult::Type::NUM, "blocks",
1300 "the height of the most-work fully-validated chain. The "
1301 "genesis block has height 0"},
1302 {RPCResult::Type::NUM, "headers",
1303 "the current number of headers we have validated"},
1304 {RPCResult::Type::STR, "bestblockhash",
1305 "the hash of the currently best block"},
1306 {RPCResult::Type::NUM, "difficulty", "the current difficulty"},
1308 "The block time expressed in " + UNIX_EPOCH_TIME},
1309 {RPCResult::Type::NUM_TIME, "mediantime",
1310 "The median block time expressed in " + UNIX_EPOCH_TIME},
1311 {RPCResult::Type::NUM, "verificationprogress",
1312 "estimate of verification progress [0..1]"},
1313 {RPCResult::Type::BOOL, "initialblockdownload",
1314 "(debug information) estimate of whether this node is in "
1315 "Initial Block Download mode"},
1316 {RPCResult::Type::STR_HEX, "chainwork",
1317 "total amount of work in active chain, in hexadecimal"},
1318 {RPCResult::Type::NUM, "size_on_disk",
1319 "the estimated size of the block and undo files on disk"},
1320 {RPCResult::Type::BOOL, "pruned",
1321 "if the blocks are subject to pruning"},
1322 {RPCResult::Type::NUM, "pruneheight",
1323 "lowest-height complete block stored (only present if pruning "
1324 "is enabled)"},
1325 {RPCResult::Type::BOOL, "automatic_pruning",
1326 "whether automatic pruning is enabled (only present if "
1327 "pruning is enabled)"},
1328 {RPCResult::Type::NUM, "prune_target_size",
1329 "the target size used by pruning (only present if automatic "
1330 "pruning is enabled)"},
1331 {RPCResult::Type::STR, "warnings",
1332 "any network and blockchain warnings"},
1333 }},
1334 RPCExamples{HelpExampleCli("getblockchaininfo", "") +
1335 HelpExampleRpc("getblockchaininfo", "")},
1336 [&](const RPCHelpMan &self, const Config &config,
1337 const JSONRPCRequest &request) -> UniValue {
1338 const CChainParams &chainparams = config.GetChainParams();
1339
1340 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1341 LOCK(cs_main);
1342 Chainstate &active_chainstate = chainman.ActiveChainstate();
1343
1344 const CBlockIndex &tip{
1345 *CHECK_NONFATAL(active_chainstate.m_chain.Tip())};
1346 const int height{tip.nHeight};
1347
1349 obj.pushKV("chain", chainparams.NetworkIDString());
1350 obj.pushKV("blocks", height);
1351 obj.pushKV("headers", chainman.m_best_header
1352 ? chainman.m_best_header->nHeight
1353 : -1);
1354 obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex());
1355 obj.pushKV("difficulty", GetDifficulty(&tip));
1356 obj.pushKV("time", tip.GetBlockTime());
1357 obj.pushKV("mediantime", tip.GetMedianTimePast());
1358 obj.pushKV(
1359 "verificationprogress",
1360 GuessVerificationProgress(chainman.GetParams().TxData(), &tip));
1361 obj.pushKV("initialblockdownload",
1362 active_chainstate.IsInitialBlockDownload());
1363 obj.pushKV("chainwork", tip.nChainWork.GetHex());
1364 obj.pushKV("size_on_disk",
1366 obj.pushKV("pruned", chainman.m_blockman.IsPruneMode());
1367
1368 if (chainman.m_blockman.IsPruneMode()) {
1369 obj.pushKV(
1370 "pruneheight",
1371 chainman.m_blockman.GetFirstStoredBlock(tip)->nHeight);
1372
1373 const bool automatic_pruning{
1374 chainman.m_blockman.GetPruneTarget() !=
1375 BlockManager::PRUNE_TARGET_MANUAL};
1376 obj.pushKV("automatic_pruning", automatic_pruning);
1377 if (automatic_pruning) {
1378 obj.pushKV("prune_target_size",
1379 chainman.m_blockman.GetPruneTarget());
1380 }
1381 }
1382
1383 obj.pushKV("warnings", GetWarnings(false).original);
1384 return obj;
1385 },
1386 };
1387}
1388
1391 bool operator()(const CBlockIndex *a, const CBlockIndex *b) const {
1392 // Make sure that unequal blocks with the same height do not compare
1393 // equal. Use the pointers themselves to make a distinction.
1394 if (a->nHeight != b->nHeight) {
1395 return (a->nHeight > b->nHeight);
1396 }
1397
1398 return a < b;
1399 }
1400};
1401
1403 return RPCHelpMan{
1404 "getchaintips",
1405 "Return information about all known tips in the block tree, including "
1406 "the main chain as well as orphaned branches.\n",
1407 {},
1408 RPCResult{
1410 "",
1411 "",
1413 "",
1414 "",
1415 {
1416 {RPCResult::Type::NUM, "height", "height of the chain tip"},
1417 {RPCResult::Type::STR_HEX, "hash", "block hash of the tip"},
1418 {RPCResult::Type::NUM, "branchlen",
1419 "zero for main chain, otherwise length of branch connecting "
1420 "the tip to the main chain"},
1421 {RPCResult::Type::STR, "status",
1422 "status of the chain, \"active\" for the main chain\n"
1423 "Possible values for status:\n"
1424 "1. \"invalid\" This branch contains at "
1425 "least one invalid block\n"
1426 "2. \"parked\" This branch contains at "
1427 "least one parked block\n"
1428 "3. \"headers-only\" Not all blocks for this "
1429 "branch are available, but the headers are valid\n"
1430 "4. \"valid-headers\" All blocks are available for "
1431 "this branch, but they were never fully validated\n"
1432 "5. \"valid-fork\" This branch is not part of "
1433 "the active chain, but is fully validated\n"
1434 "6. \"active\" This is the tip of the "
1435 "active main chain, which is certainly valid"},
1436 }}}},
1437 RPCExamples{HelpExampleCli("getchaintips", "") +
1438 HelpExampleRpc("getchaintips", "")},
1439 [&](const RPCHelpMan &self, const Config &config,
1440 const JSONRPCRequest &request) -> UniValue {
1441 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1442 LOCK(cs_main);
1443 CChain &active_chain = chainman.ActiveChain();
1444
1456 std::set<const CBlockIndex *, CompareBlocksByHeight> setTips;
1457 std::set<const CBlockIndex *> setOrphans;
1458 std::set<const CBlockIndex *> setPrevs;
1459
1460 for (const auto &[_, block_index] : chainman.BlockIndex()) {
1461 if (!active_chain.Contains(&block_index)) {
1462 setOrphans.insert(&block_index);
1463 setPrevs.insert(block_index.pprev);
1464 }
1465 }
1466
1467 for (std::set<const CBlockIndex *>::iterator it =
1468 setOrphans.begin();
1469 it != setOrphans.end(); ++it) {
1470 if (setPrevs.erase(*it) == 0) {
1471 setTips.insert(*it);
1472 }
1473 }
1474
1475 // Always report the currently active tip.
1476 setTips.insert(active_chain.Tip());
1477
1478 /* Construct the output array. */
1480 for (const CBlockIndex *block : setTips) {
1482 obj.pushKV("height", block->nHeight);
1483 obj.pushKV("hash", block->phashBlock->GetHex());
1484
1485 const int branchLen =
1486 block->nHeight - active_chain.FindFork(block)->nHeight;
1487 obj.pushKV("branchlen", branchLen);
1488
1489 std::string status;
1490 if (active_chain.Contains(block)) {
1491 // This block is part of the currently active chain.
1492 status = "active";
1493 } else if (block->nStatus.isInvalid()) {
1494 // This block or one of its ancestors is invalid.
1495 status = "invalid";
1496 } else if (block->nStatus.isOnParkedChain()) {
1497 // This block or one of its ancestors is parked.
1498 status = "parked";
1499 } else if (!block->HaveTxsDownloaded()) {
1500 // This block cannot be connected because full block data
1501 // for it or one of its parents is missing.
1502 status = "headers-only";
1503 } else if (block->IsValid(BlockValidity::SCRIPTS)) {
1504 // This block is fully validated, but no longer part of the
1505 // active chain. It was probably the active block once, but
1506 // was reorganized.
1507 status = "valid-fork";
1508 } else if (block->IsValid(BlockValidity::TREE)) {
1509 // The headers for this block are valid, but it has not been
1510 // validated. It was probably never part of the most-work
1511 // chain.
1512 status = "valid-headers";
1513 } else {
1514 // No clue.
1515 status = "unknown";
1516 }
1517 obj.pushKV("status", status);
1518
1519 res.push_back(obj);
1520 }
1521
1522 return res;
1523 },
1524 };
1525}
1526
1528 return RPCHelpMan{
1529 "preciousblock",
1530 "Treats a block as if it were received before others with the same "
1531 "work.\n"
1532 "\nA later preciousblock call can override the effect of an earlier "
1533 "one.\n"
1534 "\nThe effects of preciousblock are not retained across restarts.\n",
1535 {
1537 "the hash of the block to mark as precious"},
1538 },
1540 RPCExamples{HelpExampleCli("preciousblock", "\"blockhash\"") +
1541 HelpExampleRpc("preciousblock", "\"blockhash\"")},
1542 [&](const RPCHelpMan &self, const Config &config,
1543 const JSONRPCRequest &request) -> UniValue {
1544 BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1545 CBlockIndex *pblockindex;
1546
1547 NodeContext &node = EnsureAnyNodeContext(request.context);
1549 {
1550 LOCK(cs_main);
1551 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1552 if (!pblockindex) {
1554 "Block not found");
1555 }
1556 }
1557
1559 chainman.ActiveChainstate().PreciousBlock(state, pblockindex,
1560 node.avalanche.get());
1561
1562 if (!state.IsValid()) {
1564 }
1565
1566 // Block to make sure wallet/indexers sync before returning
1568
1569 return NullUniValue;
1570 },
1571 };
1572}
1573
1575 return RPCHelpMan{
1576 "invalidateblock",
1577 "Permanently marks a block as invalid, as if it violated a consensus "
1578 "rule.\n",
1579 {
1581 "the hash of the block to mark as invalid"},
1582 },
1584 RPCExamples{HelpExampleCli("invalidateblock", "\"blockhash\"") +
1585 HelpExampleRpc("invalidateblock", "\"blockhash\"")},
1586 [&](const RPCHelpMan &self, const Config &config,
1587 const JSONRPCRequest &request) -> UniValue {
1588 const BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1590
1591 NodeContext &node = EnsureAnyNodeContext(request.context);
1593 CBlockIndex *pblockindex;
1594 {
1595 LOCK(cs_main);
1596 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1597 if (!pblockindex) {
1599 "Block not found");
1600 }
1601 }
1602 chainman.ActiveChainstate().InvalidateBlock(state, pblockindex);
1603
1604 if (state.IsValid()) {
1605 chainman.ActiveChainstate().ActivateBestChain(
1606 state, /*pblock=*/nullptr, node.avalanche.get());
1607 }
1608
1609 if (!state.IsValid()) {
1611 }
1612
1613 // Block to make sure wallet/indexers sync before returning
1615
1616 return NullUniValue;
1617 },
1618 };
1619}
1620
1622 return RPCHelpMan{
1623 "parkblock",
1624 "Marks a block as parked.\n",
1625 {
1627 "the hash of the block to park"},
1628 },
1630 RPCExamples{HelpExampleCli("parkblock", "\"blockhash\"") +
1631 HelpExampleRpc("parkblock", "\"blockhash\"")},
1632 [&](const RPCHelpMan &self, const Config &config,
1633 const JSONRPCRequest &request) -> UniValue {
1634 const std::string strHash = request.params[0].get_str();
1635 const BlockHash hash(uint256S(strHash));
1637
1638 NodeContext &node = EnsureAnyNodeContext(request.context);
1640 Chainstate &active_chainstate = chainman.ActiveChainstate();
1641 CBlockIndex *pblockindex = nullptr;
1642 {
1643 LOCK(cs_main);
1644 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1645 if (!pblockindex) {
1647 "Block not found");
1648 }
1649
1650 if (active_chainstate.IsBlockAvalancheFinalized(pblockindex)) {
1651 // Reset avalanche finalization if we park a finalized
1652 // block.
1653 active_chainstate.ClearAvalancheFinalizedBlock();
1654 }
1655 }
1656
1657 active_chainstate.ParkBlock(state, pblockindex);
1658
1659 if (state.IsValid()) {
1660 active_chainstate.ActivateBestChain(state, /*pblock=*/nullptr,
1661 node.avalanche.get());
1662 }
1663
1664 if (!state.IsValid()) {
1666 }
1667
1668 // Block to make sure wallet/indexers sync before returning
1670
1671 return NullUniValue;
1672 },
1673 };
1674}
1675
1677 return RPCHelpMan{
1678 "reconsiderblock",
1679 "Removes invalidity status of a block, its ancestors and its"
1680 "descendants, reconsider them for activation.\n"
1681 "This can be used to undo the effects of invalidateblock.\n",
1682 {
1684 "the hash of the block to reconsider"},
1685 },
1687 RPCExamples{HelpExampleCli("reconsiderblock", "\"blockhash\"") +
1688 HelpExampleRpc("reconsiderblock", "\"blockhash\"")},
1689 [&](const RPCHelpMan &self, const Config &config,
1690 const JSONRPCRequest &request) -> UniValue {
1691 NodeContext &node = EnsureAnyNodeContext(request.context);
1693 const BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1694
1695 {
1696 LOCK(cs_main);
1697 CBlockIndex *pblockindex =
1698 chainman.m_blockman.LookupBlockIndex(hash);
1699 if (!pblockindex) {
1701 "Block not found");
1702 }
1703
1704 chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex);
1705 }
1706
1708 chainman.ActiveChainstate().ActivateBestChain(
1709 state, /*pblock=*/nullptr, node.avalanche.get());
1710
1711 if (!state.IsValid()) {
1713 }
1714
1715 // Block to make sure wallet/indexers sync before returning
1717
1718 return NullUniValue;
1719 },
1720 };
1721}
1722
1724 return RPCHelpMan{
1725 "unparkblock",
1726 "Removes parked status of a block and its descendants, reconsider "
1727 "them for activation.\n"
1728 "This can be used to undo the effects of parkblock.\n",
1729 {
1731 "the hash of the block to unpark"},
1732 },
1734 RPCExamples{HelpExampleCli("unparkblock", "\"blockhash\"") +
1735 HelpExampleRpc("unparkblock", "\"blockhash\"")},
1736 [&](const RPCHelpMan &self, const Config &config,
1737 const JSONRPCRequest &request) -> UniValue {
1738 const std::string strHash = request.params[0].get_str();
1739 NodeContext &node = EnsureAnyNodeContext(request.context);
1741 const BlockHash hash(uint256S(strHash));
1742 Chainstate &active_chainstate = chainman.ActiveChainstate();
1743
1744 {
1745 LOCK(cs_main);
1746
1747 CBlockIndex *pblockindex =
1748 chainman.m_blockman.LookupBlockIndex(hash);
1749 if (!pblockindex) {
1751 "Block not found");
1752 }
1753
1754 if (!pblockindex->nStatus.isOnParkedChain()) {
1755 // Block to unpark is not parked so there is nothing to do.
1756 return NullUniValue;
1757 }
1758
1759 const CBlockIndex *tip = active_chainstate.m_chain.Tip();
1760 if (tip) {
1761 const CBlockIndex *ancestor =
1762 LastCommonAncestor(tip, pblockindex);
1763 if (active_chainstate.IsBlockAvalancheFinalized(ancestor)) {
1764 // Only reset avalanche finalization if we unpark a
1765 // block that might conflict with avalanche finalized
1766 // blocks.
1767 active_chainstate.ClearAvalancheFinalizedBlock();
1768 }
1769 }
1770
1771 active_chainstate.UnparkBlockAndChildren(pblockindex);
1772 }
1773
1775 active_chainstate.ActivateBestChain(state, /*pblock=*/nullptr,
1776 node.avalanche.get());
1777
1778 if (!state.IsValid()) {
1780 }
1781
1782 // Block to make sure wallet/indexers sync before returning
1784
1785 return NullUniValue;
1786 },
1787 };
1788}
1789
1791 return RPCHelpMan{
1792 "getchaintxstats",
1793 "Compute statistics about the total number and rate of transactions "
1794 "in the chain.\n",
1795 {
1796 {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{"one month"},
1797 "Size of the window in number of blocks"},
1798 {"blockhash", RPCArg::Type::STR_HEX,
1799 RPCArg::DefaultHint{"chain tip"},
1800 "The hash of the block that ends the window."},
1801 },
1803 "",
1804 "",
1805 {
1807 "The timestamp for the final block in the window, "
1808 "expressed in " +
1810 {RPCResult::Type::NUM, "txcount",
1811 "The total number of transactions in the chain up to "
1812 "that point"},
1813 {RPCResult::Type::STR_HEX, "window_final_block_hash",
1814 "The hash of the final block in the window"},
1815 {RPCResult::Type::NUM, "window_final_block_height",
1816 "The height of the final block in the window."},
1817 {RPCResult::Type::NUM, "window_block_count",
1818 "Size of the window in number of blocks"},
1819 {RPCResult::Type::NUM, "window_tx_count",
1820 "The number of transactions in the window. Only "
1821 "returned if \"window_block_count\" is > 0"},
1822 {RPCResult::Type::NUM, "window_interval",
1823 "The elapsed time in the window in seconds. Only "
1824 "returned if \"window_block_count\" is > 0"},
1825 {RPCResult::Type::NUM, "txrate",
1826 "The average rate of transactions per second in the "
1827 "window. Only returned if \"window_interval\" is > 0"},
1828 }},
1829 RPCExamples{HelpExampleCli("getchaintxstats", "") +
1830 HelpExampleRpc("getchaintxstats", "2016")},
1831 [&](const RPCHelpMan &self, const Config &config,
1832 const JSONRPCRequest &request) -> UniValue {
1833 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1834 const CBlockIndex *pindex;
1835
1836 // By default: 1 month
1837 int blockcount =
1838 30 * 24 * 60 * 60 /
1839 config.GetChainParams().GetConsensus().nPowTargetSpacing;
1840
1841 if (request.params[1].isNull()) {
1842 LOCK(cs_main);
1843 pindex = chainman.ActiveTip();
1844 } else {
1845 BlockHash hash(ParseHashV(request.params[1], "blockhash"));
1846 LOCK(cs_main);
1847 pindex = chainman.m_blockman.LookupBlockIndex(hash);
1848 if (!pindex) {
1850 "Block not found");
1851 }
1852 if (!chainman.ActiveChain().Contains(pindex)) {
1854 "Block is not in main chain");
1855 }
1856 }
1857
1858 CHECK_NONFATAL(pindex != nullptr);
1859
1860 if (request.params[0].isNull()) {
1861 blockcount =
1862 std::max(0, std::min(blockcount, pindex->nHeight - 1));
1863 } else {
1864 blockcount = request.params[0].getInt<int>();
1865
1866 if (blockcount < 0 ||
1867 (blockcount > 0 && blockcount >= pindex->nHeight)) {
1869 "Invalid block count: "
1870 "should be between 0 and "
1871 "the block's height - 1");
1872 }
1873 }
1874
1875 const CBlockIndex &past_block{*CHECK_NONFATAL(
1876 pindex->GetAncestor(pindex->nHeight - blockcount))};
1877 const int64_t nTimeDiff{pindex->GetMedianTimePast() -
1878 past_block.GetMedianTimePast()};
1879 const int nTxDiff =
1880 pindex->GetChainTxCount() - past_block.GetChainTxCount();
1881
1883 ret.pushKV("time", pindex->GetBlockTime());
1884 ret.pushKV("txcount", pindex->GetChainTxCount());
1885 ret.pushKV("window_final_block_hash",
1886 pindex->GetBlockHash().GetHex());
1887 ret.pushKV("window_final_block_height", pindex->nHeight);
1888 ret.pushKV("window_block_count", blockcount);
1889 if (blockcount > 0) {
1890 ret.pushKV("window_tx_count", nTxDiff);
1891 ret.pushKV("window_interval", nTimeDiff);
1892 if (nTimeDiff > 0) {
1893 ret.pushKV("txrate", double(nTxDiff) / nTimeDiff);
1894 }
1895 }
1896
1897 return ret;
1898 },
1899 };
1900}
1901
1902template <typename T>
1903static T CalculateTruncatedMedian(std::vector<T> &scores) {
1904 size_t size = scores.size();
1905 if (size == 0) {
1906 return T();
1907 }
1908
1909 std::sort(scores.begin(), scores.end());
1910 if (size % 2 == 0) {
1911 return (scores[size / 2 - 1] + scores[size / 2]) / 2;
1912 } else {
1913 return scores[size / 2];
1914 }
1915}
1916
1917template <typename T> static inline bool SetHasKeys(const std::set<T> &set) {
1918 return false;
1919}
1920template <typename T, typename Tk, typename... Args>
1921static inline bool SetHasKeys(const std::set<T> &set, const Tk &key,
1922 const Args &...args) {
1923 return (set.count(key) != 0) || SetHasKeys(set, args...);
1924}
1925
1926// outpoint (needed for the utxo index) + nHeight + fCoinBase
1927static constexpr size_t PER_UTXO_OVERHEAD =
1928 sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);
1929
1931 const auto &ticker = Currency::get().ticker;
1932 return RPCHelpMan{
1933 "getblockstats",
1934 "Compute per block statistics for a given window. All amounts are "
1935 "in " +
1936 ticker +
1937 ".\n"
1938 "It won't work for some heights with pruning.\n",
1939 {
1940 {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO,
1941 "The block hash or height of the target block",
1943 .type_str = {"", "string or numeric"}}},
1944 {"stats",
1946 RPCArg::DefaultHint{"all values"},
1947 "Values to plot (see result below)",
1948 {
1950 "Selected statistic"},
1952 "Selected statistic"},
1953 },
1955 },
1956 RPCResult{
1958 "",
1959 "",
1960 {
1961 {RPCResult::Type::NUM, "avgfee", "Average fee in the block"},
1962 {RPCResult::Type::NUM, "avgfeerate",
1963 "Average feerate (in satoshis per virtual byte)"},
1964 {RPCResult::Type::NUM, "avgtxsize", "Average transaction size"},
1965 {RPCResult::Type::STR_HEX, "blockhash",
1966 "The block hash (to check for potential reorgs)"},
1967 {RPCResult::Type::NUM, "height", "The height of the block"},
1968 {RPCResult::Type::NUM, "ins",
1969 "The number of inputs (excluding coinbase)"},
1970 {RPCResult::Type::NUM, "maxfee", "Maximum fee in the block"},
1971 {RPCResult::Type::NUM, "maxfeerate",
1972 "Maximum feerate (in satoshis per virtual byte)"},
1973 {RPCResult::Type::NUM, "maxtxsize", "Maximum transaction size"},
1974 {RPCResult::Type::NUM, "medianfee",
1975 "Truncated median fee in the block"},
1976 {RPCResult::Type::NUM, "medianfeerate",
1977 "Truncated median feerate (in " + ticker + " per byte)"},
1978 {RPCResult::Type::NUM, "mediantime",
1979 "The block median time past"},
1980 {RPCResult::Type::NUM, "mediantxsize",
1981 "Truncated median transaction size"},
1982 {RPCResult::Type::NUM, "minfee", "Minimum fee in the block"},
1983 {RPCResult::Type::NUM, "minfeerate",
1984 "Minimum feerate (in satoshis per virtual byte)"},
1985 {RPCResult::Type::NUM, "mintxsize", "Minimum transaction size"},
1986 {RPCResult::Type::NUM, "outs", "The number of outputs"},
1987 {RPCResult::Type::NUM, "subsidy", "The block subsidy"},
1988 {RPCResult::Type::NUM, "time", "The block time"},
1989 {RPCResult::Type::NUM, "total_out",
1990 "Total amount in all outputs (excluding coinbase and thus "
1991 "reward [ie subsidy + totalfee])"},
1992 {RPCResult::Type::NUM, "total_size",
1993 "Total size of all non-coinbase transactions"},
1994 {RPCResult::Type::NUM, "totalfee", "The fee total"},
1995 {RPCResult::Type::NUM, "txs",
1996 "The number of transactions (including coinbase)"},
1997 {RPCResult::Type::NUM, "utxo_increase",
1998 "The increase/decrease in the number of unspent outputs"},
1999 {RPCResult::Type::NUM, "utxo_size_inc",
2000 "The increase/decrease in size for the utxo index (not "
2001 "discounting op_return and similar)"},
2002 }},
2005 "getblockstats",
2006 R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
2007 HelpExampleCli("getblockstats",
2008 R"(1000 '["minfeerate","avgfeerate"]')") +
2010 "getblockstats",
2011 R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") +
2012 HelpExampleRpc("getblockstats",
2013 R"(1000, ["minfeerate","avgfeerate"])")},
2014 [&](const RPCHelpMan &self, const Config &config,
2015 const JSONRPCRequest &request) -> UniValue {
2016 ChainstateManager &chainman = EnsureAnyChainman(request.context);
2017 const CBlockIndex &pindex{*CHECK_NONFATAL(
2018 ParseHashOrHeight(request.params[0], chainman))};
2019
2020 std::set<std::string> stats;
2021 if (!request.params[1].isNull()) {
2022 const UniValue stats_univalue = request.params[1].get_array();
2023 for (unsigned int i = 0; i < stats_univalue.size(); i++) {
2024 const std::string stat = stats_univalue[i].get_str();
2025 stats.insert(stat);
2026 }
2027 }
2028
2029 const CBlock &block = GetBlockChecked(chainman.m_blockman, &pindex);
2030 const CBlockUndo &blockUndo =
2031 GetUndoChecked(chainman.m_blockman, &pindex);
2032
2033 // Calculate everything if nothing selected (default)
2034 const bool do_all = stats.size() == 0;
2035 const bool do_mediantxsize =
2036 do_all || stats.count("mediantxsize") != 0;
2037 const bool do_medianfee = do_all || stats.count("medianfee") != 0;
2038 const bool do_medianfeerate =
2039 do_all || stats.count("medianfeerate") != 0;
2040 const bool loop_inputs =
2041 do_all || do_medianfee || do_medianfeerate ||
2042 SetHasKeys(stats, "utxo_size_inc", "totalfee", "avgfee",
2043 "avgfeerate", "minfee", "maxfee", "minfeerate",
2044 "maxfeerate");
2045 const bool loop_outputs =
2046 do_all || loop_inputs || stats.count("total_out");
2047 const bool do_calculate_size =
2048 do_mediantxsize || loop_inputs ||
2049 SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize",
2050 "maxtxsize");
2051
2052 const int64_t blockMaxSize = config.GetMaxBlockSize();
2053 Amount maxfee = Amount::zero();
2054 Amount maxfeerate = Amount::zero();
2055 Amount minfee = MAX_MONEY;
2056 Amount minfeerate = MAX_MONEY;
2057 Amount total_out = Amount::zero();
2058 Amount totalfee = Amount::zero();
2059 int64_t inputs = 0;
2060 int64_t maxtxsize = 0;
2061 int64_t mintxsize = blockMaxSize;
2062 int64_t outputs = 0;
2063 int64_t total_size = 0;
2064 int64_t utxo_size_inc = 0;
2065 std::vector<Amount> fee_array;
2066 std::vector<Amount> feerate_array;
2067 std::vector<int64_t> txsize_array;
2068
2069 for (size_t i = 0; i < block.vtx.size(); ++i) {
2070 const auto &tx = block.vtx.at(i);
2071 outputs += tx->vout.size();
2072 Amount tx_total_out = Amount::zero();
2073 if (loop_outputs) {
2074 for (const CTxOut &out : tx->vout) {
2075 tx_total_out += out.nValue;
2076 utxo_size_inc +=
2079 }
2080 }
2081
2082 if (tx->IsCoinBase()) {
2083 continue;
2084 }
2085
2086 // Don't count coinbase's fake input
2087 inputs += tx->vin.size();
2088 // Don't count coinbase reward
2089 total_out += tx_total_out;
2090
2091 int64_t tx_size = 0;
2092 if (do_calculate_size) {
2093 tx_size = tx->GetTotalSize();
2094 if (do_mediantxsize) {
2095 txsize_array.push_back(tx_size);
2096 }
2097 maxtxsize = std::max(maxtxsize, tx_size);
2098 mintxsize = std::min(mintxsize, tx_size);
2099 total_size += tx_size;
2100 }
2101
2102 if (loop_inputs) {
2103 Amount tx_total_in = Amount::zero();
2104 const auto &txundo = blockUndo.vtxundo.at(i - 1);
2105 for (const Coin &coin : txundo.vprevout) {
2106 const CTxOut &prevoutput = coin.GetTxOut();
2107
2108 tx_total_in += prevoutput.nValue;
2109 utxo_size_inc -=
2110 GetSerializeSize(prevoutput, PROTOCOL_VERSION) +
2112 }
2113
2114 Amount txfee = tx_total_in - tx_total_out;
2115 CHECK_NONFATAL(MoneyRange(txfee));
2116 if (do_medianfee) {
2117 fee_array.push_back(txfee);
2118 }
2119 maxfee = std::max(maxfee, txfee);
2120 minfee = std::min(minfee, txfee);
2121 totalfee += txfee;
2122
2123 Amount feerate = txfee / tx_size;
2124 if (do_medianfeerate) {
2125 feerate_array.push_back(feerate);
2126 }
2127 maxfeerate = std::max(maxfeerate, feerate);
2128 minfeerate = std::min(minfeerate, feerate);
2129 }
2130 }
2131
2132 UniValue ret_all(UniValue::VOBJ);
2133 ret_all.pushKV("avgfee",
2134 block.vtx.size() > 1
2135 ? (totalfee / int((block.vtx.size() - 1)))
2136 : Amount::zero());
2137 ret_all.pushKV("avgfeerate", total_size > 0
2138 ? (totalfee / total_size)
2139 : Amount::zero());
2140 ret_all.pushKV("avgtxsize",
2141 (block.vtx.size() > 1)
2142 ? total_size / (block.vtx.size() - 1)
2143 : 0);
2144 ret_all.pushKV("blockhash", pindex.GetBlockHash().GetHex());
2145 ret_all.pushKV("height", (int64_t)pindex.nHeight);
2146 ret_all.pushKV("ins", inputs);
2147 ret_all.pushKV("maxfee", maxfee);
2148 ret_all.pushKV("maxfeerate", maxfeerate);
2149 ret_all.pushKV("maxtxsize", maxtxsize);
2150 ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
2151 ret_all.pushKV("medianfeerate",
2152 CalculateTruncatedMedian(feerate_array));
2153 ret_all.pushKV("mediantime", pindex.GetMedianTimePast());
2154 ret_all.pushKV("mediantxsize",
2155 CalculateTruncatedMedian(txsize_array));
2156 ret_all.pushKV("minfee",
2157 minfee == MAX_MONEY ? Amount::zero() : minfee);
2158 ret_all.pushKV("minfeerate", minfeerate == MAX_MONEY
2159 ? Amount::zero()
2160 : minfeerate);
2161 ret_all.pushKV("mintxsize",
2162 mintxsize == blockMaxSize ? 0 : mintxsize);
2163 ret_all.pushKV("outs", outputs);
2164 ret_all.pushKV("subsidy", GetBlockSubsidy(pindex.nHeight,
2165 chainman.GetConsensus()));
2166 ret_all.pushKV("time", pindex.GetBlockTime());
2167 ret_all.pushKV("total_out", total_out);
2168 ret_all.pushKV("total_size", total_size);
2169 ret_all.pushKV("totalfee", totalfee);
2170 ret_all.pushKV("txs", (int64_t)block.vtx.size());
2171 ret_all.pushKV("utxo_increase", outputs - inputs);
2172 ret_all.pushKV("utxo_size_inc", utxo_size_inc);
2173
2174 if (do_all) {
2175 return ret_all;
2176 }
2177
2179 for (const std::string &stat : stats) {
2180 const UniValue &value = ret_all[stat];
2181 if (value.isNull()) {
2182 throw JSONRPCError(
2184 strprintf("Invalid selected statistic %s", stat));
2185 }
2186 ret.pushKV(stat, value);
2187 }
2188 return ret;
2189 },
2190 };
2191}
2192
2193namespace {
2195static bool FindScriptPubKey(std::atomic<int> &scan_progress,
2196 const std::atomic<bool> &should_abort,
2197 int64_t &count, CCoinsViewCursor *cursor,
2198 const std::set<CScript> &needles,
2199 std::map<COutPoint, Coin> &out_results,
2200 std::function<void()> &interruption_point) {
2201 scan_progress = 0;
2202 count = 0;
2203 while (cursor->Valid()) {
2204 COutPoint key;
2205 Coin coin;
2206 if (!cursor->GetKey(key) || !cursor->GetValue(coin)) {
2207 return false;
2208 }
2209 if (++count % 8192 == 0) {
2210 interruption_point();
2211 if (should_abort) {
2212 // allow to abort the scan via the abort reference
2213 return false;
2214 }
2215 }
2216 if (count % 256 == 0) {
2217 // update progress reference every 256 item
2218 const TxId &txid = key.GetTxId();
2219 uint32_t high = 0x100 * *txid.begin() + *(txid.begin() + 1);
2220 scan_progress = int(high * 100.0 / 65536.0 + 0.5);
2221 }
2222 if (needles.count(coin.GetTxOut().scriptPubKey)) {
2223 out_results.emplace(key, coin);
2224 }
2225 cursor->Next();
2226 }
2227 scan_progress = 100;
2228 return true;
2229}
2230} // namespace
2231
2233static std::atomic<int> g_scan_progress;
2234static std::atomic<bool> g_scan_in_progress;
2235static std::atomic<bool> g_should_abort_scan;
2237private:
2239
2240public:
2242
2243 bool reserve() {
2245 if (g_scan_in_progress.exchange(true)) {
2246 return false;
2247 }
2248 m_could_reserve = true;
2249 return true;
2250 }
2251
2253 if (m_could_reserve) {
2254 g_scan_in_progress = false;
2255 }
2256 }
2257};
2258
2260 const auto &ticker = Currency::get().ticker;
2261 return RPCHelpMan{
2262 "scantxoutset",
2263 "Scans the unspent transaction output set for entries that match "
2264 "certain output descriptors.\n"
2265 "Examples of output descriptors are:\n"
2266 " addr(<address>) Outputs whose scriptPubKey "
2267 "corresponds to the specified address (does not include P2PK)\n"
2268 " raw(<hex script>) Outputs whose scriptPubKey "
2269 "equals the specified hex scripts\n"
2270 " combo(<pubkey>) P2PK and P2PKH outputs for "
2271 "the given pubkey\n"
2272 " pkh(<pubkey>) P2PKH outputs for the given "
2273 "pubkey\n"
2274 " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for "
2275 "the given threshold and pubkeys\n"
2276 "\nIn the above, <pubkey> either refers to a fixed public key in "
2277 "hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
2278 "or more path elements separated by \"/\", and optionally ending in "
2279 "\"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
2280 "unhardened or hardened child keys.\n"
2281 "In the latter case, a range needs to be specified by below if "
2282 "different from 1000.\n"
2283 "For more information on output descriptors, see the documentation in "
2284 "the doc/descriptors.md file.\n",
2285 {
2287 "The action to execute\n"
2288 " \"start\" for starting a "
2289 "scan\n"
2290 " \"abort\" for aborting the "
2291 "current scan (returns true when abort was successful)\n"
2292 " \"status\" for "
2293 "progress report (in %) of the current scan"},
2294 {"scanobjects",
2297 "Array of scan objects. Required for \"start\" action\n"
2298 " Every scan object is either a "
2299 "string descriptor or an object:",
2300 {
2302 "An output descriptor"},
2303 {
2304 "",
2307 "An object with output descriptor and metadata",
2308 {
2310 "An output descriptor"},
2311 {"range", RPCArg::Type::RANGE, RPCArg::Default{1000},
2312 "The range of HD chain indexes to explore (either "
2313 "end or [begin,end])"},
2314 },
2315 },
2316 },
2317 RPCArgOptions{.oneline_description = "[scanobjects,...]"}},
2318 },
2319 {
2320 RPCResult{"When action=='abort'", RPCResult::Type::BOOL, "", ""},
2321 RPCResult{"When action=='status' and no scan is in progress",
2322 RPCResult::Type::NONE, "", ""},
2323 RPCResult{
2324 "When action=='status' and scan is in progress",
2326 "",
2327 "",
2328 {
2329 {RPCResult::Type::NUM, "progress", "The scan progress"},
2330 }},
2331 RPCResult{
2332 "When action=='start'",
2334 "",
2335 "",
2336 {
2337 {RPCResult::Type::BOOL, "success",
2338 "Whether the scan was completed"},
2339 {RPCResult::Type::NUM, "txouts",
2340 "The number of unspent transaction outputs scanned"},
2341 {RPCResult::Type::NUM, "height",
2342 "The current block height (index)"},
2343 {RPCResult::Type::STR_HEX, "bestblock",
2344 "The hash of the block at the tip of the chain"},
2346 "unspents",
2347 "",
2348 {
2350 "",
2351 "",
2352 {
2353 {RPCResult::Type::STR_HEX, "txid",
2354 "The transaction id"},
2355 {RPCResult::Type::NUM, "vout", "The vout value"},
2356 {RPCResult::Type::STR_HEX, "scriptPubKey",
2357 "The script key"},
2358 {RPCResult::Type::STR, "desc",
2359 "A specialized descriptor for the matched "
2360 "scriptPubKey"},
2361 {RPCResult::Type::STR_AMOUNT, "amount",
2362 "The total amount in " + ticker +
2363 " of the unspent output"},
2364 {RPCResult::Type::BOOL, "coinbase",
2365 "Whether this is a coinbase output"},
2366 {RPCResult::Type::NUM, "height",
2367 "Height of the unspent transaction output"},
2368 }},
2369 }},
2370 {RPCResult::Type::STR_AMOUNT, "total_amount",
2371 "The total amount of all found unspent outputs in " +
2372 ticker},
2373 }},
2374 },
2375 RPCExamples{""},
2376 [&](const RPCHelpMan &self, const Config &config,
2377 const JSONRPCRequest &request) -> UniValue {
2378 UniValue result(UniValue::VOBJ);
2379 if (request.params[0].get_str() == "status") {
2380 CoinsViewScanReserver reserver;
2381 if (reserver.reserve()) {
2382 // no scan in progress
2383 return NullUniValue;
2384 }
2385 result.pushKV("progress", g_scan_progress.load());
2386 return result;
2387 } else if (request.params[0].get_str() == "abort") {
2388 CoinsViewScanReserver reserver;
2389 if (reserver.reserve()) {
2390 // reserve was possible which means no scan was running
2391 return false;
2392 }
2393 // set the abort flag
2394 g_should_abort_scan = true;
2395 return true;
2396 } else if (request.params[0].get_str() == "start") {
2397 CoinsViewScanReserver reserver;
2398 if (!reserver.reserve()) {
2400 "Scan already in progress, use action "
2401 "\"abort\" or \"status\"");
2402 }
2403
2404 if (request.params.size() < 2) {
2406 "scanobjects argument is required for "
2407 "the start action");
2408 }
2409
2410 std::set<CScript> needles;
2411 std::map<CScript, std::string> descriptors;
2412 Amount total_in = Amount::zero();
2413
2414 // loop through the scan objects
2415 for (const UniValue &scanobject :
2416 request.params[1].get_array().getValues()) {
2417 FlatSigningProvider provider;
2418 auto scripts =
2419 EvalDescriptorStringOrObject(scanobject, provider);
2420 for (CScript &script : scripts) {
2421 std::string inferred =
2422 InferDescriptor(script, provider)->ToString();
2423 needles.emplace(script);
2424 descriptors.emplace(std::move(script),
2425 std::move(inferred));
2426 }
2427 }
2428
2429 // Scan the unspent transaction output set for inputs
2430 UniValue unspents(UniValue::VARR);
2431 std::vector<CTxOut> input_txos;
2432 std::map<COutPoint, Coin> coins;
2433 g_should_abort_scan = false;
2434 g_scan_progress = 0;
2435 int64_t count = 0;
2436 std::unique_ptr<CCoinsViewCursor> pcursor;
2437 const CBlockIndex *tip;
2438 NodeContext &node = EnsureAnyNodeContext(request.context);
2439 {
2441 LOCK(cs_main);
2442 Chainstate &active_chainstate = chainman.ActiveChainstate();
2443 active_chainstate.ForceFlushStateToDisk();
2444 pcursor = CHECK_NONFATAL(std::unique_ptr<CCoinsViewCursor>(
2445 active_chainstate.CoinsDB().Cursor()));
2446 tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
2447 }
2448 bool res = FindScriptPubKey(
2449 g_scan_progress, g_should_abort_scan, count, pcursor.get(),
2450 needles, coins, node.rpc_interruption_point);
2451 result.pushKV("success", res);
2452 result.pushKV("txouts", count);
2453 result.pushKV("height", tip->nHeight);
2454 result.pushKV("bestblock", tip->GetBlockHash().GetHex());
2455
2456 for (const auto &it : coins) {
2457 const COutPoint &outpoint = it.first;
2458 const Coin &coin = it.second;
2459 const CTxOut &txo = coin.GetTxOut();
2460 input_txos.push_back(txo);
2461 total_in += txo.nValue;
2462
2463 UniValue unspent(UniValue::VOBJ);
2464 unspent.pushKV("txid", outpoint.GetTxId().GetHex());
2465 unspent.pushKV("vout", int32_t(outpoint.GetN()));
2466 unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
2467 unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
2468 unspent.pushKV("amount", txo.nValue);
2469 unspent.pushKV("coinbase", coin.IsCoinBase());
2470 unspent.pushKV("height", int32_t(coin.GetHeight()));
2471
2472 unspents.push_back(unspent);
2473 }
2474 result.pushKV("unspents", unspents);
2475 result.pushKV("total_amount", total_in);
2476 } else {
2477 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid command");
2478 }
2479 return result;
2480 },
2481 };
2482}
2483
2485 return RPCHelpMan{
2486 "getblockfilter",
2487 "Retrieve a BIP 157 content filter for a particular block.\n",
2488 {
2490 "The hash of the block"},
2491 {"filtertype", RPCArg::Type::STR, RPCArg::Default{"basic"},
2492 "The type name of the filter"},
2493 },
2495 "",
2496 "",
2497 {
2498 {RPCResult::Type::STR_HEX, "filter",
2499 "the hex-encoded filter data"},
2500 {RPCResult::Type::STR_HEX, "header",
2501 "the hex-encoded filter header"},
2502 }},
2504 HelpExampleCli("getblockfilter",
2505 "\"00000000c937983704a73af28acdec37b049d214a"
2506 "dbda81d7e2a3dd146f6ed09\" \"basic\"") +
2507 HelpExampleRpc("getblockfilter",
2508 "\"00000000c937983704a73af28acdec37b049d214adbda81d7"
2509 "e2a3dd146f6ed09\", \"basic\"")},
2510 [&](const RPCHelpMan &self, const Config &config,
2511 const JSONRPCRequest &request) -> UniValue {
2512 const BlockHash block_hash(
2513 ParseHashV(request.params[0], "blockhash"));
2514 std::string filtertype_name = "basic";
2515 if (!request.params[1].isNull()) {
2516 filtertype_name = request.params[1].get_str();
2517 }
2518
2519 BlockFilterType filtertype;
2520 if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2522 "Unknown filtertype");
2523 }
2524
2525 BlockFilterIndex *index = GetBlockFilterIndex(filtertype);
2526 if (!index) {
2528 "Index is not enabled for filtertype " +
2529 filtertype_name);
2530 }
2531
2532 const CBlockIndex *block_index;
2533 bool block_was_connected;
2534 {
2535 ChainstateManager &chainman =
2536 EnsureAnyChainman(request.context);
2537 LOCK(cs_main);
2538 block_index = chainman.m_blockman.LookupBlockIndex(block_hash);
2539 if (!block_index) {
2541 "Block not found");
2542 }
2543 block_was_connected =
2544 block_index->IsValid(BlockValidity::SCRIPTS);
2545 }
2546
2547 bool index_ready = index->BlockUntilSyncedToCurrentChain();
2548
2549 BlockFilter filter;
2550 uint256 filter_header;
2551 if (!index->LookupFilter(block_index, filter) ||
2552 !index->LookupFilterHeader(block_index, filter_header)) {
2553 int err_code;
2554 std::string errmsg = "Filter not found.";
2555
2556 if (!block_was_connected) {
2557 err_code = RPC_INVALID_ADDRESS_OR_KEY;
2558 errmsg += " Block was not connected to active chain.";
2559 } else if (!index_ready) {
2560 err_code = RPC_MISC_ERROR;
2561 errmsg += " Block filters are still in the process of "
2562 "being indexed.";
2563 } else {
2564 err_code = RPC_INTERNAL_ERROR;
2565 errmsg += " This error is unexpected and indicates index "
2566 "corruption.";
2567 }
2568
2569 throw JSONRPCError(err_code, errmsg);
2570 }
2571
2573 ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
2574 ret.pushKV("header", filter_header.GetHex());
2575 return ret;
2576 },
2577 };
2578}
2579
2586 return RPCHelpMan{
2587 "dumptxoutset",
2588 "Write the serialized UTXO set to disk.\n",
2589 {
2591 "path to the output file. If relative, will be prefixed by "
2592 "datadir."},
2593 },
2595 "",
2596 "",
2597 {
2598 {RPCResult::Type::NUM, "coins_written",
2599 "the number of coins written in the snapshot"},
2600 {RPCResult::Type::STR_HEX, "base_hash",
2601 "the hash of the base of the snapshot"},
2602 {RPCResult::Type::NUM, "base_height",
2603 "the height of the base of the snapshot"},
2604 {RPCResult::Type::STR, "path",
2605 "the absolute path that the snapshot was written to"},
2606 {RPCResult::Type::STR_HEX, "txoutset_hash",
2607 "the hash of the UTXO set contents"},
2608 {RPCResult::Type::NUM, "nchaintx",
2609 "the number of transactions in the chain up to and "
2610 "including the base block"},
2611 }},
2612 RPCExamples{HelpExampleCli("dumptxoutset", "utxo.dat")},
2613 [&](const RPCHelpMan &self, const Config &config,
2614 const JSONRPCRequest &request) -> UniValue {
2615 const ArgsManager &args{EnsureAnyArgsman(request.context)};
2616 const fs::path path = fsbridge::AbsPathJoin(
2617 args.GetDataDirNet(), fs::u8path(request.params[0].get_str()));
2618 // Write to a temporary path and then move into `path` on completion
2619 // to avoid confusion due to an interruption.
2620 const fs::path temppath = fsbridge::AbsPathJoin(
2621 args.GetDataDirNet(),
2622 fs::u8path(request.params[0].get_str() + ".incomplete"));
2623
2624 if (fs::exists(path)) {
2626 path.u8string() +
2627 " already exists. If you are sure this "
2628 "is what you want, "
2629 "move it out of the way first");
2630 }
2631
2632 FILE *file{fsbridge::fopen(temppath, "wb")};
2633 AutoFile afile{file};
2634 NodeContext &node = EnsureAnyNodeContext(request.context);
2636 node, node.chainman->ActiveChainstate(), afile, path, temppath);
2637 fs::rename(temppath, path);
2638
2639 return result;
2640 },
2641 };
2642}
2643
2645 AutoFile &afile, const fs::path &path,
2646 const fs::path &temppath) {
2647 std::unique_ptr<CCoinsViewCursor> pcursor;
2648 std::optional<CCoinsStats> maybe_stats;
2649 const CBlockIndex *tip;
2650
2651 {
2652 // We need to lock cs_main to ensure that the coinsdb isn't
2653 // written to between (i) flushing coins cache to disk
2654 // (coinsdb), (ii) getting stats based upon the coinsdb, and
2655 // (iii) constructing a cursor to the coinsdb for use below this
2656 // block.
2657 //
2658 // Cursors returned by leveldb iterate over snapshots, so the
2659 // contents of the pcursor will not be affected by simultaneous
2660 // writes during use below this block.
2661 //
2662 // See discussion here:
2663 // https://github.com/bitcoin/bitcoin/pull/15606#discussion_r274479369
2664 //
2665 LOCK(::cs_main);
2666
2667 chainstate.ForceFlushStateToDisk();
2668
2669 maybe_stats = GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman,
2670 CoinStatsHashType::HASH_SERIALIZED,
2671 node.rpc_interruption_point);
2672 if (!maybe_stats) {
2673 throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
2674 }
2675
2676 pcursor =
2677 std::unique_ptr<CCoinsViewCursor>(chainstate.CoinsDB().Cursor());
2678 tip = CHECK_NONFATAL(
2679 chainstate.m_blockman.LookupBlockIndex(maybe_stats->hashBlock));
2680 }
2681
2683 strprintf("writing UTXO snapshot at height %s (%s) to file %s (via %s)",
2684 tip->nHeight, tip->GetBlockHash().ToString(),
2685 fs::PathToString(path), fs::PathToString(temppath)));
2686
2687 SnapshotMetadata metadata{tip->GetBlockHash(), maybe_stats->coins_count,
2688 uint64_t(tip->GetChainTxCount())};
2689
2690 afile << metadata;
2691
2692 COutPoint key;
2693 Coin coin;
2694 unsigned int iter{0};
2695
2696 while (pcursor->Valid()) {
2697 if (iter % 5000 == 0) {
2698 node.rpc_interruption_point();
2699 }
2700 ++iter;
2701 if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
2702 afile << key;
2703 afile << coin;
2704 }
2705
2706 pcursor->Next();
2707 }
2708
2709 afile.fclose();
2710
2711 UniValue result(UniValue::VOBJ);
2712 result.pushKV("coins_written", maybe_stats->coins_count);
2713 result.pushKV("base_hash", tip->GetBlockHash().ToString());
2714 result.pushKV("base_height", tip->nHeight);
2715 result.pushKV("path", path.u8string());
2716 result.pushKV("txoutset_hash", maybe_stats->hashSerialized.ToString());
2717 // Cast required because univalue doesn't have serialization specified for
2718 // `unsigned int`, nChainTx's type.
2719 result.pushKV("nchaintx", uint64_t{tip->nChainTx});
2720 return result;
2721}
2722
2724 // clang-format off
2725 static const CRPCCommand commands[] = {
2726 // category actor (function)
2727 // ------------------ ----------------------
2728 { "blockchain", getbestblockhash, },
2729 { "blockchain", getblock, },
2730 { "blockchain", getblockfrompeer, },
2731 { "blockchain", getblockchaininfo, },
2732 { "blockchain", getblockcount, },
2733 { "blockchain", getblockhash, },
2734 { "blockchain", getblockheader, },
2735 { "blockchain", getblockstats, },
2736 { "blockchain", getchaintips, },
2737 { "blockchain", getchaintxstats, },
2738 { "blockchain", getdifficulty, },
2739 { "blockchain", gettxout, },
2740 { "blockchain", gettxoutsetinfo, },
2741 { "blockchain", pruneblockchain, },
2742 { "blockchain", verifychain, },
2743 { "blockchain", preciousblock, },
2744 { "blockchain", scantxoutset, },
2745 { "blockchain", getblockfilter, },
2746
2747 /* Not shown in help */
2748 { "hidden", invalidateblock, },
2749 { "hidden", parkblock, },
2750 { "hidden", reconsiderblock, },
2751 { "hidden", syncwithvalidationinterfacequeue, },
2752 { "hidden", dumptxoutset, },
2753 { "hidden", unparkblock, },
2754 { "hidden", waitfornewblock, },
2755 { "hidden", waitforblock, },
2756 { "hidden", waitforblockheight, },
2757 };
2758 // clang-format on
2759 for (const auto &c : commands) {
2760 t.appendCommand(c.name, &c);
2761 }
2762}
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:907
static RPCHelpMan getblockstats()
static CoinStatsHashType ParseHashType(const std::string &hash_type_input)
Definition: blockchain.cpp:893
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:211
uint256 hashMerkleRoot
Definition: blockindex.h:91
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: blockindex.h:32
CBlockHeader GetBlockHeader() const
Definition: blockindex.h:133
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:154
uint32_t nTime
Definition: blockindex.h:92
uint32_t nNonce
Definition: blockindex.h:94
int64_t GetBlockTime() const
Definition: blockindex.h:180
int64_t GetMedianTimePast() const
Definition: blockindex.h:192
uint32_t nBits
Definition: blockindex.h:93
unsigned int nTx
Number of transactions in this block.
Definition: blockindex.h:60
int32_t nVersion
block header
Definition: blockindex.h:90
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition: blockindex.cpp:78
BlockHash GetBlockHash() const
Definition: blockindex.h:146
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:77
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:80
std::string NetworkIDString() const
Return the BIP70 network string (main, test or regtest)
Definition: chainparams.h:127
const ChainTxData & TxData() const
Definition: chainparams.h:140
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:618
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
GetCoin, returning whether it exists and is not spent.
Definition: txmempool.cpp:610
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:212
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:307
bool isSpent(const COutPoint &outpoint) const
Definition: txmempool.cpp:133
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:620
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:699
bool IsBlockAvalancheFinalized(const CBlockIndex *pindex) const EXCLUSIVE_LOCKS_REQUIRED(!cs_avalancheFinalizedBlockIndex)
Checks if a block is finalized by avalanche voting.
CChain m_chain
The current chain of blockheaders we consult and build on.
Definition: validation.h:808
bool IsInitialBlockDownload() const
Check whether we are doing an initial block download (synchronizing from disk or network)
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:834
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:841
node::BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all Chainstate instances.
Definition: validation.h:772
bool ActivateBestChain(BlockValidationState &state, std::shared_ptr< const CBlock > pblock=nullptr, avalanche::Processor *const avalanche=nullptr, bool skip_checkblockindex=false) EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex
Find the best known block, and make it the tip of the block chain.
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:1219
node::BlockMap & BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:1439
kernel::Notifications & GetNotifications() const
Definition: validation.h:1328
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1435
SnapshotCompletionResult MaybeCompleteSnapshotValidation(std::function< void(bilingual_str)> shutdown_fnc=[](bilingual_str msg) { AbortNode(msg.original, msg);}) EXCLUSIVE_LOCKS_REQUIRED(Chainstate & ActiveChainstate() const
Once the background validation chainstate has reached the height which is the base of the UTXO snapsh...
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1432
const CChainParams & GetParams() const
Definition: validation.h:1313
const Consensus::Params & GetConsensus() const
Definition: validation.h:1316
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1429
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1351
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:238
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:235
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:211
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:28
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:43
#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:48
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:98
void PruneBlockFilesManual(Chainstate &active_chainstate, int nManualPruneHeight)
Prune block files up to a given height.
static constexpr int DEFAULT_CHECKLEVEL
Definition: validation.h:97
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:95
static const signed int DEFAULT_CHECKBLOCKS
Definition: validation.h:96
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