Bitcoin ABC 0.31.2
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 <clientversion.h>
12#include <coins.h>
13#include <common/args.h>
14#include <config.h>
15#include <consensus/amount.h>
16#include <consensus/params.h>
18#include <core_io.h>
19#include <hash.h>
22#include <logging/timer.h>
23#include <net.h>
24#include <net_processing.h>
25#include <node/blockstorage.h>
26#include <node/coinstats.h>
27#include <node/context.h>
28#include <node/utxo_snapshot.h>
30#include <rpc/server.h>
31#include <rpc/server_util.h>
32#include <rpc/util.h>
33#include <script/descriptor.h>
34#include <serialize.h>
35#include <streams.h>
36#include <txdb.h>
37#include <txmempool.h>
38#include <undo.h>
39#include <util/check.h>
40#include <util/fs.h>
41#include <util/strencodings.h>
42#include <util/translation.h>
43#include <validation.h>
44#include <validationinterface.h>
45#include <warnings.h>
46
47#include <condition_variable>
48#include <cstdint>
49#include <memory>
50#include <mutex>
51
54
59
62 int height;
63};
64
66static std::condition_variable cond_blockchange;
68
72double GetDifficulty(const CBlockIndex *blockindex) {
73 CHECK_NONFATAL(blockindex);
74
75 int nShift = (blockindex->nBits >> 24) & 0xff;
76 double dDiff = double(0x0000ffff) / double(blockindex->nBits & 0x00ffffff);
77
78 while (nShift < 29) {
79 dDiff *= 256.0;
80 nShift++;
81 }
82 while (nShift > 29) {
83 dDiff /= 256.0;
84 nShift--;
85 }
86
87 return dDiff;
88}
89
91 const CBlockIndex *blockindex,
92 const CBlockIndex *&next) {
93 next = tip->GetAncestor(blockindex->nHeight + 1);
94 if (next && next->pprev == blockindex) {
95 return tip->nHeight - blockindex->nHeight + 1;
96 }
97 next = nullptr;
98 return blockindex == tip ? 1 : -1;
99}
100
101static const CBlockIndex *ParseHashOrHeight(const UniValue &param,
102 ChainstateManager &chainman) {
104 CChain &active_chain = chainman.ActiveChain();
105
106 if (param.isNum()) {
107 const int height{param.getInt<int>()};
108 if (height < 0) {
109 throw JSONRPCError(
111 strprintf("Target block height %d is negative", height));
112 }
113 const int current_tip{active_chain.Height()};
114 if (height > current_tip) {
115 throw JSONRPCError(
117 strprintf("Target block height %d after current tip %d", height,
118 current_tip));
119 }
120
121 return active_chain[height];
122 } else {
123 const BlockHash hash{ParseHashV(param, "hash_or_height")};
124 const CBlockIndex *pindex = chainman.m_blockman.LookupBlockIndex(hash);
125
126 if (!pindex) {
127 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
128 }
129
130 return pindex;
131 }
132}
134 const CBlockIndex *blockindex) {
135 // Serialize passed information without accessing chain state of the active
136 // chain!
137 // For performance reasons
139
140 UniValue result(UniValue::VOBJ);
141 result.pushKV("hash", blockindex->GetBlockHash().GetHex());
142 const CBlockIndex *pnext;
143 int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
144 result.pushKV("confirmations", confirmations);
145 result.pushKV("height", blockindex->nHeight);
146 result.pushKV("version", blockindex->nVersion);
147 result.pushKV("versionHex", strprintf("%08x", blockindex->nVersion));
148 result.pushKV("merkleroot", blockindex->hashMerkleRoot.GetHex());
149 result.pushKV("time", int64_t(blockindex->nTime));
150 result.pushKV("mediantime", int64_t(blockindex->GetMedianTimePast()));
151 result.pushKV("nonce", uint64_t(blockindex->nNonce));
152 result.pushKV("bits", strprintf("%08x", blockindex->nBits));
153 result.pushKV("difficulty", GetDifficulty(blockindex));
154 result.pushKV("chainwork", blockindex->nChainWork.GetHex());
155 result.pushKV("nTx", uint64_t(blockindex->nTx));
156
157 if (blockindex->pprev) {
158 result.pushKV("previousblockhash",
159 blockindex->pprev->GetBlockHash().GetHex());
160 }
161 if (pnext) {
162 result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
163 }
164 return result;
165}
166
167UniValue blockToJSON(BlockManager &blockman, const CBlock &block,
168 const CBlockIndex *tip, const CBlockIndex *blockindex,
169 bool txDetails) {
170 UniValue result = blockheaderToJSON(tip, blockindex);
171
172 result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION));
174 if (txDetails) {
175 CBlockUndo blockUndo;
176 const bool is_not_pruned{
177 WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))};
178 const bool have_undo{is_not_pruned &&
179 blockman.UndoReadFromDisk(blockUndo, *blockindex)};
180 for (size_t i = 0; i < block.vtx.size(); ++i) {
181 const CTransactionRef &tx = block.vtx.at(i);
182 // coinbase transaction (i == 0) doesn't have undo data
183 const CTxUndo *txundo =
184 (have_undo && i) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
186 TxToUniv(*tx, BlockHash(), objTx, true, RPCSerializationFlags(),
187 txundo);
188 txs.push_back(objTx);
189 }
190 } else {
191 for (const CTransactionRef &tx : block.vtx) {
192 txs.push_back(tx->GetId().GetHex());
193 }
194 }
195 result.pushKV("tx", txs);
196
197 return result;
198}
199
201 return RPCHelpMan{
202 "getblockcount",
203 "Returns the height of the most-work fully-validated chain.\n"
204 "The genesis block has height 0.\n",
205 {},
206 RPCResult{RPCResult::Type::NUM, "", "The current block count"},
207 RPCExamples{HelpExampleCli("getblockcount", "") +
208 HelpExampleRpc("getblockcount", "")},
209 [&](const RPCHelpMan &self, const Config &config,
210 const JSONRPCRequest &request) -> UniValue {
211 ChainstateManager &chainman = EnsureAnyChainman(request.context);
212 LOCK(cs_main);
213 return chainman.ActiveHeight();
214 },
215 };
216}
217
219 return RPCHelpMan{
220 "getbestblockhash",
221 "Returns the hash of the best (tip) block in the "
222 "most-work fully-validated chain.\n",
223 {},
224 RPCResult{RPCResult::Type::STR_HEX, "", "the block hash, hex-encoded"},
225 RPCExamples{HelpExampleCli("getbestblockhash", "") +
226 HelpExampleRpc("getbestblockhash", "")},
227 [&](const RPCHelpMan &self, const Config &config,
228 const JSONRPCRequest &request) -> UniValue {
229 ChainstateManager &chainman = EnsureAnyChainman(request.context);
230 LOCK(cs_main);
231 return chainman.ActiveTip()->GetBlockHash().GetHex();
232 },
233 };
234}
235
237 if (pindex) {
239 latestblock.hash = pindex->GetBlockHash();
240 latestblock.height = pindex->nHeight;
241 }
242 cond_blockchange.notify_all();
243}
244
246 return RPCHelpMan{
247 "waitfornewblock",
248 "Waits for a specific new block and returns useful info about it.\n"
249 "\nReturns the current block on timeout or exit.\n",
250 {
251 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0},
252 "Time in milliseconds to wait for a response. 0 indicates no "
253 "timeout."},
254 },
256 "",
257 "",
258 {
259 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
260 {RPCResult::Type::NUM, "height", "Block height"},
261 }},
262 RPCExamples{HelpExampleCli("waitfornewblock", "1000") +
263 HelpExampleRpc("waitfornewblock", "1000")},
264 [&](const RPCHelpMan &self, const Config &config,
265 const JSONRPCRequest &request) -> UniValue {
266 int timeout = 0;
267 if (!request.params[0].isNull()) {
268 timeout = request.params[0].getInt<int>();
269 }
270
271 CUpdatedBlock block;
272 {
274 block = latestblock;
275 if (timeout) {
276 cond_blockchange.wait_for(
277 lock, std::chrono::milliseconds(timeout),
279 return latestblock.height != block.height ||
280 latestblock.hash != block.hash ||
281 !IsRPCRunning();
282 });
283 } else {
284 cond_blockchange.wait(
285 lock,
287 return latestblock.height != block.height ||
288 latestblock.hash != block.hash ||
289 !IsRPCRunning();
290 });
291 }
292 block = latestblock;
293 }
295 ret.pushKV("hash", block.hash.GetHex());
296 ret.pushKV("height", block.height);
297 return ret;
298 },
299 };
300}
301
303 return RPCHelpMan{
304 "waitforblock",
305 "Waits for a specific new block and returns useful info about it.\n"
306 "\nReturns the current block on timeout or exit.\n",
307 {
309 "Block hash to wait for."},
310 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0},
311 "Time in milliseconds to wait for a response. 0 indicates no "
312 "timeout."},
313 },
315 "",
316 "",
317 {
318 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
319 {RPCResult::Type::NUM, "height", "Block height"},
320 }},
321 RPCExamples{HelpExampleCli("waitforblock",
322 "\"0000000000079f8ef3d2c688c244eb7a4570b24c9"
323 "ed7b4a8c619eb02596f8862\" 1000") +
324 HelpExampleRpc("waitforblock",
325 "\"0000000000079f8ef3d2c688c244eb7a4570b24c9"
326 "ed7b4a8c619eb02596f8862\", 1000")},
327 [&](const RPCHelpMan &self, const Config &config,
328 const JSONRPCRequest &request) -> UniValue {
329 int timeout = 0;
330
331 BlockHash hash(ParseHashV(request.params[0], "blockhash"));
332
333 if (!request.params[1].isNull()) {
334 timeout = request.params[1].getInt<int>();
335 }
336
337 CUpdatedBlock block;
338 {
340 if (timeout) {
341 cond_blockchange.wait_for(
342 lock, std::chrono::milliseconds(timeout),
344 return latestblock.hash == hash || !IsRPCRunning();
345 });
346 } else {
347 cond_blockchange.wait(
348 lock,
350 return latestblock.hash == hash || !IsRPCRunning();
351 });
352 }
353 block = latestblock;
354 }
355
357 ret.pushKV("hash", block.hash.GetHex());
358 ret.pushKV("height", block.height);
359 return ret;
360 },
361 };
362}
363
365 return RPCHelpMan{
366 "waitforblockheight",
367 "Waits for (at least) block height and returns the height and "
368 "hash\nof the current tip.\n"
369 "\nReturns the current block on timeout or exit.\n",
370 {
372 "Block height to wait for."},
373 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0},
374 "Time in milliseconds to wait for a response. 0 indicates no "
375 "timeout."},
376 },
378 "",
379 "",
380 {
381 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
382 {RPCResult::Type::NUM, "height", "Block height"},
383 }},
384 RPCExamples{HelpExampleCli("waitforblockheight", "100 1000") +
385 HelpExampleRpc("waitforblockheight", "100, 1000")},
386 [&](const RPCHelpMan &self, const Config &config,
387 const JSONRPCRequest &request) -> UniValue {
388 int timeout = 0;
389
390 int height = request.params[0].getInt<int>();
391
392 if (!request.params[1].isNull()) {
393 timeout = request.params[1].getInt<int>();
394 }
395
396 CUpdatedBlock block;
397 {
399 if (timeout) {
400 cond_blockchange.wait_for(
401 lock, std::chrono::milliseconds(timeout),
403 return latestblock.height >= height ||
404 !IsRPCRunning();
405 });
406 } else {
407 cond_blockchange.wait(
408 lock,
410 return latestblock.height >= height ||
411 !IsRPCRunning();
412 });
413 }
414 block = latestblock;
415 }
417 ret.pushKV("hash", block.hash.GetHex());
418 ret.pushKV("height", block.height);
419 return ret;
420 },
421 };
422}
423
425 return RPCHelpMan{
426 "syncwithvalidationinterfacequeue",
427 "Waits for the validation interface queue to catch up on everything "
428 "that was there when we entered this function.\n",
429 {},
431 RPCExamples{HelpExampleCli("syncwithvalidationinterfacequeue", "") +
432 HelpExampleRpc("syncwithvalidationinterfacequeue", "")},
433 [&](const RPCHelpMan &self, const Config &config,
434 const JSONRPCRequest &request) -> UniValue {
436 return NullUniValue;
437 },
438 };
439}
440
442 return RPCHelpMan{
443 "getdifficulty",
444 "Returns the proof-of-work difficulty as a multiple of the minimum "
445 "difficulty.\n",
446 {},
448 "the proof-of-work difficulty as a multiple of the minimum "
449 "difficulty."},
450 RPCExamples{HelpExampleCli("getdifficulty", "") +
451 HelpExampleRpc("getdifficulty", "")},
452 [&](const RPCHelpMan &self, const Config &config,
453 const JSONRPCRequest &request) -> UniValue {
454 ChainstateManager &chainman = EnsureAnyChainman(request.context);
455 LOCK(cs_main);
456 return GetDifficulty(chainman.ActiveTip());
457 },
458 };
459}
460
462 return RPCHelpMan{
463 "getblockfrompeer",
464 "Attempt to fetch block from a given peer.\n"
465 "\nWe must have the header for this block, e.g. using submitheader.\n"
466 "The block will not have any undo data which can limit the usage of "
467 "the block data in a context where the undo data is needed.\n"
468 "Subsequent calls for the same block may cause the response from the "
469 "previous peer to be ignored.\n"
470 "\nReturns an empty JSON object if the request was successfully "
471 "scheduled.",
472 {
474 "The block hash to try to fetch"},
476 "The peer to fetch it from (see getpeerinfo for peer IDs)"},
477 },
478 RPCResult{RPCResult::Type::OBJ, "", /*optional=*/false, "", {}},
479 RPCExamples{HelpExampleCli("getblockfrompeer",
480 "\"00000000c937983704a73af28acdec37b049d214a"
481 "dbda81d7e2a3dd146f6ed09\" 0") +
482 HelpExampleRpc("getblockfrompeer",
483 "\"00000000c937983704a73af28acdec37b049d214a"
484 "dbda81d7e2a3dd146f6ed09\" 0")},
485 [&](const RPCHelpMan &self, const Config &config,
486 const JSONRPCRequest &request) -> UniValue {
487 const NodeContext &node = EnsureAnyNodeContext(request.context);
489 PeerManager &peerman = EnsurePeerman(node);
490
491 const BlockHash block_hash{
492 ParseHashV(request.params[0], "blockhash")};
493 const NodeId peer_id{request.params[1].getInt<int64_t>()};
494
495 const CBlockIndex *const index = WITH_LOCK(
496 cs_main,
497 return chainman.m_blockman.LookupBlockIndex(block_hash););
498
499 if (!index) {
500 throw JSONRPCError(RPC_MISC_ERROR, "Block header missing");
501 }
502
503 if (WITH_LOCK(::cs_main, return index->nStatus.hasData())) {
504 throw JSONRPCError(RPC_MISC_ERROR, "Block already downloaded");
505 }
506
507 if (const auto err{peerman.FetchBlock(config, peer_id, *index)}) {
508 throw JSONRPCError(RPC_MISC_ERROR, err.value());
509 }
510 return UniValue::VOBJ;
511 },
512 };
513}
514
516 return RPCHelpMan{
517 "getblockhash",
518 "Returns hash of block in best-block-chain at height provided.\n",
519 {
521 "The height index"},
522 },
523 RPCResult{RPCResult::Type::STR_HEX, "", "The block hash"},
524 RPCExamples{HelpExampleCli("getblockhash", "1000") +
525 HelpExampleRpc("getblockhash", "1000")},
526 [&](const RPCHelpMan &self, const Config &config,
527 const JSONRPCRequest &request) -> UniValue {
528 ChainstateManager &chainman = EnsureAnyChainman(request.context);
529 LOCK(cs_main);
530 const CChain &active_chain = chainman.ActiveChain();
531
532 int nHeight = request.params[0].getInt<int>();
533 if (nHeight < 0 || nHeight > active_chain.Height()) {
535 "Block height out of range");
536 }
537
538 const CBlockIndex *pblockindex = active_chain[nHeight];
539 return pblockindex->GetBlockHash().GetHex();
540 },
541 };
542}
543
545 return RPCHelpMan{
546 "getblockheader",
547 "If verbose is false, returns a string that is serialized, hex-encoded "
548 "data for blockheader 'hash'.\n"
549 "If verbose is true, returns an Object with information about "
550 "blockheader <hash>.\n",
551 {
553 "The block hash"},
554 {"verbose", RPCArg::Type::BOOL, RPCArg::Default{true},
555 "true for a json object, false for the hex-encoded data"},
556 },
557 {
558 RPCResult{
559 "for verbose = true",
561 "",
562 "",
563 {
565 "the block hash (same as provided)"},
566 {RPCResult::Type::NUM, "confirmations",
567 "The number of confirmations, or -1 if the block is not "
568 "on the main chain"},
569 {RPCResult::Type::NUM, "height",
570 "The block height or index"},
571 {RPCResult::Type::NUM, "version", "The block version"},
572 {RPCResult::Type::STR_HEX, "versionHex",
573 "The block version formatted in hexadecimal"},
574 {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
576 "The block time expressed in " + UNIX_EPOCH_TIME},
577 {RPCResult::Type::NUM_TIME, "mediantime",
578 "The median block time expressed in " + UNIX_EPOCH_TIME},
579 {RPCResult::Type::NUM, "nonce", "The nonce"},
580 {RPCResult::Type::STR_HEX, "bits", "The bits"},
581 {RPCResult::Type::NUM, "difficulty", "The difficulty"},
582 {RPCResult::Type::STR_HEX, "chainwork",
583 "Expected number of hashes required to produce the "
584 "current chain"},
585 {RPCResult::Type::NUM, "nTx",
586 "The number of transactions in the block"},
587 {RPCResult::Type::STR_HEX, "previousblockhash",
588 /* optional */ true,
589 "The hash of the previous block (if available)"},
590 {RPCResult::Type::STR_HEX, "nextblockhash",
591 /* optional */ true,
592 "The hash of the next block (if available)"},
593 }},
594 RPCResult{"for verbose=false", RPCResult::Type::STR_HEX, "",
595 "A string that is serialized, hex-encoded data for block "
596 "'hash'"},
597 },
598 RPCExamples{HelpExampleCli("getblockheader",
599 "\"00000000c937983704a73af28acdec37b049d214a"
600 "dbda81d7e2a3dd146f6ed09\"") +
601 HelpExampleRpc("getblockheader",
602 "\"00000000c937983704a73af28acdec37b049d214a"
603 "dbda81d7e2a3dd146f6ed09\"")},
604 [&](const RPCHelpMan &self, const Config &config,
605 const JSONRPCRequest &request) -> UniValue {
606 BlockHash hash(ParseHashV(request.params[0], "hash"));
607
608 bool fVerbose = true;
609 if (!request.params[1].isNull()) {
610 fVerbose = request.params[1].get_bool();
611 }
612
613 const CBlockIndex *pblockindex;
614 const CBlockIndex *tip;
615 {
616 ChainstateManager &chainman =
617 EnsureAnyChainman(request.context);
618 LOCK(cs_main);
619 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
620 tip = chainman.ActiveTip();
621 }
622
623 if (!pblockindex) {
625 "Block not found");
626 }
627
628 if (!fVerbose) {
630 ssBlock << pblockindex->GetBlockHeader();
631 std::string strHex = HexStr(ssBlock);
632 return strHex;
633 }
634
635 return blockheaderToJSON(tip, pblockindex);
636 },
637 };
638}
639
641 const CBlockIndex *pblockindex) {
642 CBlock block;
643 {
644 LOCK(cs_main);
645 if (blockman.IsBlockPruned(pblockindex)) {
647 "Block not available (pruned data)");
648 }
649 }
650
651 if (!blockman.ReadBlockFromDisk(block, *pblockindex)) {
652 // Block not found on disk. This could be because we have the block
653 // header in our index but not yet have the block or did not accept the
654 // block. Or if the block was pruned right after we released the lock
655 // above.
656 throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
657 }
658
659 return block;
660}
661
663 const CBlockIndex *pblockindex) {
664 CBlockUndo blockUndo;
665
666 {
667 LOCK(cs_main);
668 if (blockman.IsBlockPruned(pblockindex)) {
670 "Undo data not available (pruned data)");
671 }
672 }
673
674 if (!blockman.UndoReadFromDisk(blockUndo, *pblockindex)) {
675 throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
676 }
677
678 return blockUndo;
679}
680
682 return RPCHelpMan{
683 "getblock",
684 "If verbosity is 0 or false, returns a string that is serialized, "
685 "hex-encoded data for block 'hash'.\n"
686 "If verbosity is 1 or true, returns an Object with information about "
687 "block <hash>.\n"
688 "If verbosity is 2, returns an Object with information about block "
689 "<hash> and information about each transaction.\n",
690 {
692 "The block hash"},
693 {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1},
694 "0 for hex-encoded data, 1 for a json object, and 2 for json "
695 "object with transaction data",
697 },
698 {
699 RPCResult{"for verbosity = 0", RPCResult::Type::STR_HEX, "",
700 "A string that is serialized, hex-encoded data for block "
701 "'hash'"},
702 RPCResult{
703 "for verbosity = 1",
705 "",
706 "",
707 {
709 "the block hash (same as provided)"},
710 {RPCResult::Type::NUM, "confirmations",
711 "The number of confirmations, or -1 if the block is not "
712 "on the main chain"},
713 {RPCResult::Type::NUM, "size", "The block size"},
714 {RPCResult::Type::NUM, "height",
715 "The block height or index"},
716 {RPCResult::Type::NUM, "version", "The block version"},
717 {RPCResult::Type::STR_HEX, "versionHex",
718 "The block version formatted in hexadecimal"},
719 {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
721 "tx",
722 "The transaction ids",
723 {{RPCResult::Type::STR_HEX, "", "The transaction id"}}},
725 "The block time expressed in " + UNIX_EPOCH_TIME},
726 {RPCResult::Type::NUM_TIME, "mediantime",
727 "The median block time expressed in " + UNIX_EPOCH_TIME},
728 {RPCResult::Type::NUM, "nonce", "The nonce"},
729 {RPCResult::Type::STR_HEX, "bits", "The bits"},
730 {RPCResult::Type::NUM, "difficulty", "The difficulty"},
731 {RPCResult::Type::STR_HEX, "chainwork",
732 "Expected number of hashes required to produce the chain "
733 "up to this block (in hex)"},
734 {RPCResult::Type::NUM, "nTx",
735 "The number of transactions in the block"},
736 {RPCResult::Type::STR_HEX, "previousblockhash",
737 /* optional */ true,
738 "The hash of the previous block (if available)"},
739 {RPCResult::Type::STR_HEX, "nextblockhash",
740 /* optional */ true,
741 "The hash of the next block (if available)"},
742 }},
743 RPCResult{"for verbosity = 2",
745 "",
746 "",
747 {
749 "Same output as verbosity = 1"},
751 "tx",
752 "",
753 {
755 "",
756 "",
757 {
759 "The transactions in the format of the "
760 "getrawtransaction RPC. Different from "
761 "verbosity = 1 \"tx\" result"},
763 "The transaction fee in " +
765 ", omitted if block undo data is not "
766 "available"},
767 }},
768 }},
769 }},
770 },
772 HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d"
773 "214adbda81d7e2a3dd146f6ed09\"") +
774 HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d"
775 "214adbda81d7e2a3dd146f6ed09\"")},
776 [&](const RPCHelpMan &self, const Config &config,
777 const JSONRPCRequest &request) -> UniValue {
778 BlockHash hash(ParseHashV(request.params[0], "blockhash"));
779
780 int verbosity = 1;
781 if (!request.params[1].isNull()) {
782 if (request.params[1].isNum()) {
783 verbosity = request.params[1].getInt<int>();
784 } else {
785 verbosity = request.params[1].get_bool() ? 1 : 0;
786 }
787 }
788
789 const CBlockIndex *pblockindex;
790 const CBlockIndex *tip;
791 ChainstateManager &chainman = EnsureAnyChainman(request.context);
792 {
793 LOCK(cs_main);
794 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
795 tip = chainman.ActiveTip();
796
797 if (!pblockindex) {
799 "Block not found");
800 }
801 }
802
803 const CBlock block =
804 GetBlockChecked(chainman.m_blockman, pblockindex);
805
806 if (verbosity <= 0) {
807 CDataStream ssBlock(SER_NETWORK,
809 ssBlock << block;
810 std::string strHex = HexStr(ssBlock);
811 return strHex;
812 }
813
814 return blockToJSON(chainman.m_blockman, block, tip, pblockindex,
815 verbosity >= 2);
816 },
817 };
818}
819
820std::optional<int> GetPruneHeight(const BlockManager &blockman,
821 const CChain &chain) {
823
824 // Search for the last block missing block data or undo data. Don't let the
825 // search consider the genesis block, because the genesis block does not
826 // have undo data, but should not be considered pruned.
827 const CBlockIndex *first_block{chain[1]};
828 const CBlockIndex *chain_tip{chain.Tip()};
829
830 // If there are no blocks after the genesis block, or no blocks at all,
831 // nothing is pruned.
832 if (!first_block || !chain_tip) {
833 return std::nullopt;
834 }
835
836 // If the chain tip is pruned, everything is pruned.
837 if (!(chain_tip->nStatus.hasData() && chain_tip->nStatus.hasUndo())) {
838 return chain_tip->nHeight;
839 }
840
841 // Get first block with data, after the last block without data.
842 // This is the start of the unpruned range of blocks.
843 const CBlockIndex *first_unpruned{CHECK_NONFATAL(
844 blockman.GetFirstBlock(*chain_tip,
845 /*status_test=*/[](const BlockStatus &status) {
846 return status.hasData() && status.hasUndo();
847 }))};
848 if (first_unpruned == first_block) {
849 // All blocks between first_block and chain_tip have data, so nothing is
850 // pruned.
851 return std::nullopt;
852 }
853
854 // Block before the first unpruned block is the last pruned block.
855 return CHECK_NONFATAL(first_unpruned->pprev)->nHeight;
856}
857
859 return RPCHelpMan{
860 "pruneblockchain",
861 "",
862 {
864 "The block height to prune up to. May be set to a discrete "
865 "height, or to a " +
867 "\n"
868 " to prune blocks whose block time is at "
869 "least 2 hours older than the provided timestamp."},
870 },
871 RPCResult{RPCResult::Type::NUM, "", "Height of the last block pruned"},
872 RPCExamples{HelpExampleCli("pruneblockchain", "1000") +
873 HelpExampleRpc("pruneblockchain", "1000")},
874 [&](const RPCHelpMan &self, const Config &config,
875 const JSONRPCRequest &request) -> UniValue {
876 ChainstateManager &chainman = EnsureAnyChainman(request.context);
877 if (!chainman.m_blockman.IsPruneMode()) {
878 throw JSONRPCError(
880 "Cannot prune blocks because node is not in prune mode.");
881 }
882
883 LOCK(cs_main);
884 Chainstate &active_chainstate = chainman.ActiveChainstate();
885 CChain &active_chain = active_chainstate.m_chain;
886
887 int heightParam = request.params[0].getInt<int>();
888 if (heightParam < 0) {
890 "Negative block height.");
891 }
892
893 // Height value more than a billion is too high to be a block
894 // height, and too low to be a block time (corresponds to timestamp
895 // from Sep 2001).
896 if (heightParam > 1000000000) {
897 // Add a 2 hour buffer to include blocks which might have had
898 // old timestamps
899 const CBlockIndex *pindex = active_chain.FindEarliestAtLeast(
900 heightParam - TIMESTAMP_WINDOW, 0);
901 if (!pindex) {
903 "Could not find block with at least the "
904 "specified timestamp.");
905 }
906 heightParam = pindex->nHeight;
907 }
908
909 unsigned int height = (unsigned int)heightParam;
910 unsigned int chainHeight = (unsigned int)active_chain.Height();
911 if (chainHeight < config.GetChainParams().PruneAfterHeight()) {
913 "Blockchain is too short for pruning.");
914 } else if (height > chainHeight) {
915 throw JSONRPCError(
917 "Blockchain is shorter than the attempted prune height.");
918 } else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
920 "Attempt to prune blocks close to the tip. "
921 "Retaining the minimum number of blocks.\n");
922 height = chainHeight - MIN_BLOCKS_TO_KEEP;
923 }
924
925 PruneBlockFilesManual(active_chainstate, height);
926 return GetPruneHeight(chainman.m_blockman, active_chain)
927 .value_or(-1);
928 },
929 };
930}
931
932static CoinStatsHashType ParseHashType(const std::string &hash_type_input) {
933 if (hash_type_input == "hash_serialized") {
934 return CoinStatsHashType::HASH_SERIALIZED;
935 } else if (hash_type_input == "muhash") {
936 return CoinStatsHashType::MUHASH;
937 } else if (hash_type_input == "none") {
939 } else {
940 throw JSONRPCError(
942 strprintf("%s is not a valid hash_type", hash_type_input));
943 }
944}
945
947 return RPCHelpMan{
948 "gettxoutsetinfo",
949 "Returns statistics about the unspent transaction output set.\n"
950 "Note this call may take some time if you are not using "
951 "coinstatsindex.\n",
952 {
953 {"hash_type", RPCArg::Type::STR, RPCArg::Default{"hash_serialized"},
954 "Which UTXO set hash should be calculated. Options: "
955 "'hash_serialized' (the legacy algorithm), 'muhash', 'none'."},
957 "The block hash or height of the target height (only available "
958 "with coinstatsindex).",
960 .type_str = {"", "string or numeric"}}},
961 {"use_index", RPCArg::Type::BOOL, RPCArg::Default{true},
962 "Use coinstatsindex, if available."},
963 },
964 RPCResult{
966 "",
967 "",
968 {
969 {RPCResult::Type::NUM, "height",
970 "The current block height (index)"},
971 {RPCResult::Type::STR_HEX, "bestblock",
972 "The hash of the block at the tip of the chain"},
973 {RPCResult::Type::NUM, "txouts",
974 "The number of unspent transaction outputs"},
975 {RPCResult::Type::NUM, "bogosize",
976 "Database-independent, meaningless metric indicating "
977 "the UTXO set size"},
978 {RPCResult::Type::STR_HEX, "hash_serialized",
979 /* optional */ true,
980 "The serialized hash (only present if 'hash_serialized' "
981 "hash_type is chosen)"},
982 {RPCResult::Type::STR_HEX, "muhash", /* optional */ true,
983 "The serialized hash (only present if 'muhash' "
984 "hash_type is chosen)"},
985 {RPCResult::Type::NUM, "transactions",
986 "The number of transactions with unspent outputs (not "
987 "available when coinstatsindex is used)"},
988 {RPCResult::Type::NUM, "disk_size",
989 "The estimated size of the chainstate on disk (not "
990 "available when coinstatsindex is used)"},
991 {RPCResult::Type::STR_AMOUNT, "total_amount",
992 "The total amount"},
993 {RPCResult::Type::STR_AMOUNT, "total_unspendable_amount",
994 "The total amount of coins permanently excluded from the UTXO "
995 "set (only available if coinstatsindex is used)"},
997 "block_info",
998 "Info on amounts in the block at this block height (only "
999 "available if coinstatsindex is used)",
1000 {{RPCResult::Type::STR_AMOUNT, "prevout_spent",
1001 "Total amount of all prevouts spent in this block"},
1002 {RPCResult::Type::STR_AMOUNT, "coinbase",
1003 "Coinbase subsidy amount of this block"},
1004 {RPCResult::Type::STR_AMOUNT, "new_outputs_ex_coinbase",
1005 "Total amount of new outputs created by this block"},
1006 {RPCResult::Type::STR_AMOUNT, "unspendable",
1007 "Total amount of unspendable outputs created in this block"},
1009 "unspendables",
1010 "Detailed view of the unspendable categories",
1011 {
1012 {RPCResult::Type::STR_AMOUNT, "genesis_block",
1013 "The unspendable amount of the Genesis block subsidy"},
1015 "Transactions overridden by duplicates (no longer "
1016 "possible with BIP30)"},
1017 {RPCResult::Type::STR_AMOUNT, "scripts",
1018 "Amounts sent to scripts that are unspendable (for "
1019 "example OP_RETURN outputs)"},
1020 {RPCResult::Type::STR_AMOUNT, "unclaimed_rewards",
1021 "Fee rewards that miners did not claim in their "
1022 "coinbase transaction"},
1023 }}}},
1024 }},
1026 HelpExampleCli("gettxoutsetinfo", "") +
1027 HelpExampleCli("gettxoutsetinfo", R"("none")") +
1028 HelpExampleCli("gettxoutsetinfo", R"("none" 1000)") +
1030 "gettxoutsetinfo",
1031 R"("none" '"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"')") +
1032 HelpExampleRpc("gettxoutsetinfo", "") +
1033 HelpExampleRpc("gettxoutsetinfo", R"("none")") +
1034 HelpExampleRpc("gettxoutsetinfo", R"("none", 1000)") +
1036 "gettxoutsetinfo",
1037 R"("none", "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09")")},
1038 [&](const RPCHelpMan &self, const Config &config,
1039 const JSONRPCRequest &request) -> UniValue {
1041
1042 const CBlockIndex *pindex{nullptr};
1043 const CoinStatsHashType hash_type{
1044 request.params[0].isNull()
1045 ? CoinStatsHashType::HASH_SERIALIZED
1046 : ParseHashType(request.params[0].get_str())};
1047 bool index_requested =
1048 request.params[2].isNull() || request.params[2].get_bool();
1049
1050 NodeContext &node = EnsureAnyNodeContext(request.context);
1052 Chainstate &active_chainstate = chainman.ActiveChainstate();
1053 active_chainstate.ForceFlushStateToDisk();
1054
1055 CCoinsView *coins_view;
1056 BlockManager *blockman;
1057 {
1058 LOCK(::cs_main);
1059 coins_view = &active_chainstate.CoinsDB();
1060 blockman = &active_chainstate.m_blockman;
1061 pindex = blockman->LookupBlockIndex(coins_view->GetBestBlock());
1062 }
1063
1064 if (!request.params[1].isNull()) {
1065 if (!g_coin_stats_index) {
1067 "Querying specific block heights "
1068 "requires coinstatsindex");
1069 }
1070
1071 if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1073 "hash_serialized hash type cannot be "
1074 "queried for a specific block");
1075 }
1076
1077 pindex = ParseHashOrHeight(request.params[1], chainman);
1078 }
1079
1080 if (index_requested && g_coin_stats_index) {
1081 if (!g_coin_stats_index->BlockUntilSyncedToCurrentChain()) {
1082 const IndexSummary summary{
1083 g_coin_stats_index->GetSummary()};
1084
1085 // If a specific block was requested and the index has
1086 // already synced past that height, we can return the data
1087 // already even though the index is not fully synced yet.
1088 if (pindex->nHeight > summary.best_block_height) {
1089 throw JSONRPCError(
1091 strprintf(
1092 "Unable to get data because coinstatsindex is "
1093 "still syncing. Current height: %d",
1094 summary.best_block_height));
1095 }
1096 }
1097 }
1098
1099 const std::optional<CCoinsStats> maybe_stats = GetUTXOStats(
1100 coins_view, *blockman, hash_type, node.rpc_interruption_point,
1101 pindex, index_requested);
1102 if (maybe_stats.has_value()) {
1103 const CCoinsStats &stats = maybe_stats.value();
1104 ret.pushKV("height", int64_t(stats.nHeight));
1105 ret.pushKV("bestblock", stats.hashBlock.GetHex());
1106 ret.pushKV("txouts", int64_t(stats.nTransactionOutputs));
1107 ret.pushKV("bogosize", int64_t(stats.nBogoSize));
1108 if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1109 ret.pushKV("hash_serialized",
1110 stats.hashSerialized.GetHex());
1111 }
1112 if (hash_type == CoinStatsHashType::MUHASH) {
1113 ret.pushKV("muhash", stats.hashSerialized.GetHex());
1114 }
1115 ret.pushKV("total_amount", stats.nTotalAmount);
1116 if (!stats.index_used) {
1117 ret.pushKV("transactions",
1118 static_cast<int64_t>(stats.nTransactions));
1119 ret.pushKV("disk_size", stats.nDiskSize);
1120 } else {
1121 ret.pushKV("total_unspendable_amount",
1123
1124 CCoinsStats prev_stats{};
1125 if (pindex->nHeight > 0) {
1126 const std::optional<CCoinsStats> maybe_prev_stats =
1127 GetUTXOStats(coins_view, *blockman, hash_type,
1128 node.rpc_interruption_point,
1129 pindex->pprev, index_requested);
1130 if (!maybe_prev_stats) {
1132 "Unable to read UTXO set");
1133 }
1134 prev_stats = maybe_prev_stats.value();
1135 }
1136
1137 UniValue block_info(UniValue::VOBJ);
1138 block_info.pushKV(
1139 "prevout_spent",
1141 prev_stats.total_prevout_spent_amount);
1142 block_info.pushKV("coinbase",
1143 stats.total_coinbase_amount -
1144 prev_stats.total_coinbase_amount);
1145 block_info.pushKV(
1146 "new_outputs_ex_coinbase",
1148 prev_stats.total_new_outputs_ex_coinbase_amount);
1149 block_info.pushKV("unspendable",
1151 prev_stats.total_unspendable_amount);
1152
1153 UniValue unspendables(UniValue::VOBJ);
1154 unspendables.pushKV(
1155 "genesis_block",
1157 prev_stats.total_unspendables_genesis_block);
1158 unspendables.pushKV(
1159 "bip30", stats.total_unspendables_bip30 -
1160 prev_stats.total_unspendables_bip30);
1161 unspendables.pushKV(
1162 "scripts", stats.total_unspendables_scripts -
1163 prev_stats.total_unspendables_scripts);
1164 unspendables.pushKV(
1165 "unclaimed_rewards",
1167 prev_stats.total_unspendables_unclaimed_rewards);
1168 block_info.pushKV("unspendables", unspendables);
1169
1170 ret.pushKV("block_info", block_info);
1171 }
1172 } else {
1174 "Unable to read UTXO set");
1175 }
1176 return ret;
1177 },
1178 };
1179}
1180
1182 return RPCHelpMan{
1183 "gettxout",
1184 "Returns details about an unspent transaction output.\n",
1185 {
1187 "The transaction id"},
1188 {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
1189 {"include_mempool", RPCArg::Type::BOOL, RPCArg::Default{true},
1190 "Whether to include the mempool. Note that an unspent output that "
1191 "is spent in the mempool won't appear."},
1192 },
1193 {
1194 RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "",
1195 ""},
1196 RPCResult{
1197 "Otherwise",
1199 "",
1200 "",
1201 {
1202 {RPCResult::Type::STR_HEX, "bestblock",
1203 "The hash of the block at the tip of the chain"},
1204 {RPCResult::Type::NUM, "confirmations",
1205 "The number of confirmations"},
1207 "The transaction value in " + Currency::get().ticker},
1209 "scriptPubKey",
1210 "",
1211 {
1212 {RPCResult::Type::STR_HEX, "asm", ""},
1213 {RPCResult::Type::STR_HEX, "hex", ""},
1214 {RPCResult::Type::NUM, "reqSigs",
1215 "Number of required signatures"},
1216 {RPCResult::Type::STR_HEX, "type",
1217 "The type, eg pubkeyhash"},
1219 "addresses",
1220 "array of eCash addresses",
1221 {{RPCResult::Type::STR, "address", "eCash address"}}},
1222 }},
1223 {RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
1224 }},
1225 },
1226 RPCExamples{"\nGet unspent transactions\n" +
1227 HelpExampleCli("listunspent", "") + "\nView the details\n" +
1228 HelpExampleCli("gettxout", "\"txid\" 1") +
1229 "\nAs a JSON-RPC call\n" +
1230 HelpExampleRpc("gettxout", "\"txid\", 1")},
1231 [&](const RPCHelpMan &self, const Config &config,
1232 const JSONRPCRequest &request) -> UniValue {
1233 NodeContext &node = EnsureAnyNodeContext(request.context);
1235 LOCK(cs_main);
1236
1238
1239 TxId txid(ParseHashV(request.params[0], "txid"));
1240 int n = request.params[1].getInt<int>();
1241 COutPoint out(txid, n);
1242 bool fMempool = true;
1243 if (!request.params[2].isNull()) {
1244 fMempool = request.params[2].get_bool();
1245 }
1246
1247 Coin coin;
1248 Chainstate &active_chainstate = chainman.ActiveChainstate();
1249 CCoinsViewCache *coins_view = &active_chainstate.CoinsTip();
1250
1251 if (fMempool) {
1252 const CTxMemPool &mempool = EnsureMemPool(node);
1253 LOCK(mempool.cs);
1254 CCoinsViewMemPool view(coins_view, mempool);
1255 if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
1256 return NullUniValue;
1257 }
1258 } else {
1259 if (!coins_view->GetCoin(out, coin)) {
1260 return NullUniValue;
1261 }
1262 }
1263
1264 const CBlockIndex *pindex =
1265 active_chainstate.m_blockman.LookupBlockIndex(
1266 coins_view->GetBestBlock());
1267 ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
1268 if (coin.GetHeight() == MEMPOOL_HEIGHT) {
1269 ret.pushKV("confirmations", 0);
1270 } else {
1271 ret.pushKV("confirmations",
1272 int64_t(pindex->nHeight - coin.GetHeight() + 1));
1273 }
1274 ret.pushKV("value", coin.GetTxOut().nValue);
1276 ScriptPubKeyToUniv(coin.GetTxOut().scriptPubKey, o, true);
1277 ret.pushKV("scriptPubKey", o);
1278 ret.pushKV("coinbase", coin.IsCoinBase());
1279
1280 return ret;
1281 },
1282 };
1283}
1284
1286 return RPCHelpMan{
1287 "verifychain",
1288 "Verifies blockchain database.\n",
1289 {
1290 {"checklevel", RPCArg::Type::NUM,
1292 strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL)},
1293 strprintf("How thorough the block verification is:\n - %s",
1294 Join(CHECKLEVEL_DOC, "\n- "))},
1295 {"nblocks", RPCArg::Type::NUM,
1297 "The number of blocks to check."},
1298 },
1300 "Verification finished successfully. If false, check "
1301 "debug.log for reason."},
1302 RPCExamples{HelpExampleCli("verifychain", "") +
1303 HelpExampleRpc("verifychain", "")},
1304 [&](const RPCHelpMan &self, const Config &config,
1305 const JSONRPCRequest &request) -> UniValue {
1306 const int check_level{request.params[0].isNull()
1308 : request.params[0].getInt<int>()};
1309 const int check_depth{request.params[1].isNull()
1311 : request.params[1].getInt<int>()};
1312
1313 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1314 LOCK(cs_main);
1315
1316 Chainstate &active_chainstate = chainman.ActiveChainstate();
1317 return CVerifyDB(chainman.GetNotifications())
1318 .VerifyDB(active_chainstate,
1319 active_chainstate.CoinsTip(), check_level,
1320 check_depth) == VerifyDBResult::SUCCESS;
1321 },
1322 };
1323}
1324
1326 return RPCHelpMan{
1327 "getblockchaininfo",
1328 "Returns an object containing various state info regarding blockchain "
1329 "processing.\n",
1330 {},
1331 RPCResult{
1333 "",
1334 "",
1335 {
1336 {RPCResult::Type::STR, "chain",
1337 "current network name (main, test, regtest)"},
1338 {RPCResult::Type::NUM, "blocks",
1339 "the height of the most-work fully-validated chain. The "
1340 "genesis block has height 0"},
1341 {RPCResult::Type::NUM, "headers",
1342 "the current number of headers we have validated"},
1343 {RPCResult::Type::STR, "bestblockhash",
1344 "the hash of the currently best block"},
1345 {RPCResult::Type::NUM, "difficulty", "the current difficulty"},
1347 "The block time expressed in " + UNIX_EPOCH_TIME},
1348 {RPCResult::Type::NUM_TIME, "mediantime",
1349 "The median block time expressed in " + UNIX_EPOCH_TIME},
1350 {RPCResult::Type::NUM, "verificationprogress",
1351 "estimate of verification progress [0..1]"},
1352 {RPCResult::Type::BOOL, "initialblockdownload",
1353 "(debug information) estimate of whether this node is in "
1354 "Initial Block Download mode"},
1355 {RPCResult::Type::STR_HEX, "chainwork",
1356 "total amount of work in active chain, in hexadecimal"},
1357 {RPCResult::Type::NUM, "size_on_disk",
1358 "the estimated size of the block and undo files on disk"},
1359 {RPCResult::Type::BOOL, "pruned",
1360 "if the blocks are subject to pruning"},
1361 {RPCResult::Type::NUM, "pruneheight",
1362 "lowest-height complete block stored (only present if pruning "
1363 "is enabled)"},
1364 {RPCResult::Type::BOOL, "automatic_pruning",
1365 "whether automatic pruning is enabled (only present if "
1366 "pruning is enabled)"},
1367 {RPCResult::Type::NUM, "prune_target_size",
1368 "the target size used by pruning (only present if automatic "
1369 "pruning is enabled)"},
1370 {RPCResult::Type::STR, "warnings",
1371 "any network and blockchain warnings"},
1372 }},
1373 RPCExamples{HelpExampleCli("getblockchaininfo", "") +
1374 HelpExampleRpc("getblockchaininfo", "")},
1375 [&](const RPCHelpMan &self, const Config &config,
1376 const JSONRPCRequest &request) -> UniValue {
1377 const CChainParams &chainparams = config.GetChainParams();
1378
1379 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1380 LOCK(cs_main);
1381 Chainstate &active_chainstate = chainman.ActiveChainstate();
1382
1383 const CBlockIndex &tip{
1384 *CHECK_NONFATAL(active_chainstate.m_chain.Tip())};
1385 const int height{tip.nHeight};
1386
1388 obj.pushKV("chain", chainparams.NetworkIDString());
1389 obj.pushKV("blocks", height);
1390 obj.pushKV("headers", chainman.m_best_header
1391 ? chainman.m_best_header->nHeight
1392 : -1);
1393 obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex());
1394 obj.pushKV("difficulty", GetDifficulty(&tip));
1395 obj.pushKV("time", tip.GetBlockTime());
1396 obj.pushKV("mediantime", tip.GetMedianTimePast());
1397 obj.pushKV(
1398 "verificationprogress",
1399 GuessVerificationProgress(chainman.GetParams().TxData(), &tip));
1400 obj.pushKV("initialblockdownload",
1401 chainman.IsInitialBlockDownload());
1402 obj.pushKV("chainwork", tip.nChainWork.GetHex());
1403 obj.pushKV("size_on_disk",
1405 obj.pushKV("pruned", chainman.m_blockman.IsPruneMode());
1406
1407 if (chainman.m_blockman.IsPruneMode()) {
1408 const auto prune_height{GetPruneHeight(
1409 chainman.m_blockman, active_chainstate.m_chain)};
1410 obj.pushKV("pruneheight",
1411 prune_height ? prune_height.value() + 1 : 0);
1412
1413 const bool automatic_pruning{
1414 chainman.m_blockman.GetPruneTarget() !=
1415 BlockManager::PRUNE_TARGET_MANUAL};
1416 obj.pushKV("automatic_pruning", automatic_pruning);
1417 if (automatic_pruning) {
1418 obj.pushKV("prune_target_size",
1419 chainman.m_blockman.GetPruneTarget());
1420 }
1421 }
1422
1423 obj.pushKV("warnings", GetWarnings(false).original);
1424 return obj;
1425 },
1426 };
1427}
1428
1431 bool operator()(const CBlockIndex *a, const CBlockIndex *b) const {
1432 // Make sure that unequal blocks with the same height do not compare
1433 // equal. Use the pointers themselves to make a distinction.
1434 if (a->nHeight != b->nHeight) {
1435 return (a->nHeight > b->nHeight);
1436 }
1437
1438 return a < b;
1439 }
1440};
1441
1443 return RPCHelpMan{
1444 "getchaintips",
1445 "Return information about all known tips in the block tree, including "
1446 "the main chain as well as orphaned branches.\n",
1447 {},
1448 RPCResult{
1450 "",
1451 "",
1453 "",
1454 "",
1455 {
1456 {RPCResult::Type::NUM, "height", "height of the chain tip"},
1457 {RPCResult::Type::STR_HEX, "hash", "block hash of the tip"},
1458 {RPCResult::Type::NUM, "branchlen",
1459 "zero for main chain, otherwise length of branch connecting "
1460 "the tip to the main chain"},
1461 {RPCResult::Type::STR, "status",
1462 "status of the chain, \"active\" for the main chain\n"
1463 "Possible values for status:\n"
1464 "1. \"invalid\" This branch contains at "
1465 "least one invalid block\n"
1466 "2. \"parked\" This branch contains at "
1467 "least one parked block\n"
1468 "3. \"headers-only\" Not all blocks for this "
1469 "branch are available, but the headers are valid\n"
1470 "4. \"valid-headers\" All blocks are available for "
1471 "this branch, but they were never fully validated\n"
1472 "5. \"valid-fork\" This branch is not part of "
1473 "the active chain, but is fully validated\n"
1474 "6. \"active\" This is the tip of the "
1475 "active main chain, which is certainly valid"},
1476 }}}},
1477 RPCExamples{HelpExampleCli("getchaintips", "") +
1478 HelpExampleRpc("getchaintips", "")},
1479 [&](const RPCHelpMan &self, const Config &config,
1480 const JSONRPCRequest &request) -> UniValue {
1481 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1482 LOCK(cs_main);
1483 CChain &active_chain = chainman.ActiveChain();
1484
1496 std::set<const CBlockIndex *, CompareBlocksByHeight> setTips;
1497 std::set<const CBlockIndex *> setOrphans;
1498 std::set<const CBlockIndex *> setPrevs;
1499
1500 for (const auto &[_, block_index] : chainman.BlockIndex()) {
1501 if (!active_chain.Contains(&block_index)) {
1502 setOrphans.insert(&block_index);
1503 setPrevs.insert(block_index.pprev);
1504 }
1505 }
1506
1507 for (std::set<const CBlockIndex *>::iterator it =
1508 setOrphans.begin();
1509 it != setOrphans.end(); ++it) {
1510 if (setPrevs.erase(*it) == 0) {
1511 setTips.insert(*it);
1512 }
1513 }
1514
1515 // Always report the currently active tip.
1516 setTips.insert(active_chain.Tip());
1517
1518 /* Construct the output array. */
1520 for (const CBlockIndex *block : setTips) {
1522 obj.pushKV("height", block->nHeight);
1523 obj.pushKV("hash", block->phashBlock->GetHex());
1524
1525 const int branchLen =
1526 block->nHeight - active_chain.FindFork(block)->nHeight;
1527 obj.pushKV("branchlen", branchLen);
1528
1529 std::string status;
1530 if (active_chain.Contains(block)) {
1531 // This block is part of the currently active chain.
1532 status = "active";
1533 } else if (block->nStatus.isInvalid()) {
1534 // This block or one of its ancestors is invalid.
1535 status = "invalid";
1536 } else if (block->nStatus.isOnParkedChain()) {
1537 // This block or one of its ancestors is parked.
1538 status = "parked";
1539 } else if (!block->HaveNumChainTxs()) {
1540 // This block cannot be connected because full block data
1541 // for it or one of its parents is missing.
1542 status = "headers-only";
1543 } else if (block->IsValid(BlockValidity::SCRIPTS)) {
1544 // This block is fully validated, but no longer part of the
1545 // active chain. It was probably the active block once, but
1546 // was reorganized.
1547 status = "valid-fork";
1548 } else if (block->IsValid(BlockValidity::TREE)) {
1549 // The headers for this block are valid, but it has not been
1550 // validated. It was probably never part of the most-work
1551 // chain.
1552 status = "valid-headers";
1553 } else {
1554 // No clue.
1555 status = "unknown";
1556 }
1557 obj.pushKV("status", status);
1558
1559 res.push_back(obj);
1560 }
1561
1562 return res;
1563 },
1564 };
1565}
1566
1568 return RPCHelpMan{
1569 "preciousblock",
1570 "Treats a block as if it were received before others with the same "
1571 "work.\n"
1572 "\nA later preciousblock call can override the effect of an earlier "
1573 "one.\n"
1574 "\nThe effects of preciousblock are not retained across restarts.\n",
1575 {
1577 "the hash of the block to mark as precious"},
1578 },
1580 RPCExamples{HelpExampleCli("preciousblock", "\"blockhash\"") +
1581 HelpExampleRpc("preciousblock", "\"blockhash\"")},
1582 [&](const RPCHelpMan &self, const Config &config,
1583 const JSONRPCRequest &request) -> UniValue {
1584 BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1585 CBlockIndex *pblockindex;
1586
1587 NodeContext &node = EnsureAnyNodeContext(request.context);
1589 {
1590 LOCK(cs_main);
1591 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1592 if (!pblockindex) {
1594 "Block not found");
1595 }
1596 }
1597
1599 chainman.ActiveChainstate().PreciousBlock(state, pblockindex,
1600 node.avalanche.get());
1601
1602 if (!state.IsValid()) {
1604 }
1605
1606 // Block to make sure wallet/indexers sync before returning
1608
1609 return NullUniValue;
1610 },
1611 };
1612}
1613
1615 return RPCHelpMan{
1616 "invalidateblock",
1617 "Permanently marks a block as invalid, as if it violated a consensus "
1618 "rule.\n",
1619 {
1621 "the hash of the block to mark as invalid"},
1622 },
1624 RPCExamples{HelpExampleCli("invalidateblock", "\"blockhash\"") +
1625 HelpExampleRpc("invalidateblock", "\"blockhash\"")},
1626 [&](const RPCHelpMan &self, const Config &config,
1627 const JSONRPCRequest &request) -> UniValue {
1628 const BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1630
1631 NodeContext &node = EnsureAnyNodeContext(request.context);
1633 CBlockIndex *pblockindex;
1634 {
1635 LOCK(cs_main);
1636 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1637 if (!pblockindex) {
1639 "Block not found");
1640 }
1641 }
1642 chainman.ActiveChainstate().InvalidateBlock(state, pblockindex);
1643
1644 if (state.IsValid()) {
1645 chainman.ActiveChainstate().ActivateBestChain(
1646 state, /*pblock=*/nullptr, node.avalanche.get());
1647 }
1648
1649 if (!state.IsValid()) {
1651 }
1652
1653 // Block to make sure wallet/indexers sync before returning
1655
1656 return NullUniValue;
1657 },
1658 };
1659}
1660
1662 return RPCHelpMan{
1663 "parkblock",
1664 "Marks a block as parked.\n",
1665 {
1667 "the hash of the block to park"},
1668 },
1670 RPCExamples{HelpExampleCli("parkblock", "\"blockhash\"") +
1671 HelpExampleRpc("parkblock", "\"blockhash\"")},
1672 [&](const RPCHelpMan &self, const Config &config,
1673 const JSONRPCRequest &request) -> UniValue {
1674 const std::string strHash = request.params[0].get_str();
1675 const BlockHash hash(uint256S(strHash));
1677
1678 NodeContext &node = EnsureAnyNodeContext(request.context);
1680 Chainstate &active_chainstate = chainman.ActiveChainstate();
1681 CBlockIndex *pblockindex = nullptr;
1682 {
1683 LOCK(cs_main);
1684 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1685 if (!pblockindex) {
1687 "Block not found");
1688 }
1689
1690 if (active_chainstate.IsBlockAvalancheFinalized(pblockindex)) {
1691 // Reset avalanche finalization if we park a finalized
1692 // block.
1693 active_chainstate.ClearAvalancheFinalizedBlock();
1694 }
1695 }
1696
1697 active_chainstate.ParkBlock(state, pblockindex);
1698
1699 if (state.IsValid()) {
1700 active_chainstate.ActivateBestChain(state, /*pblock=*/nullptr,
1701 node.avalanche.get());
1702 }
1703
1704 if (!state.IsValid()) {
1706 }
1707
1708 // Block to make sure wallet/indexers sync before returning
1710
1711 return NullUniValue;
1712 },
1713 };
1714}
1715
1717 return RPCHelpMan{
1718 "reconsiderblock",
1719 "Removes invalidity status of a block, its ancestors and its"
1720 "descendants, reconsider them for activation.\n"
1721 "This can be used to undo the effects of invalidateblock.\n",
1722 {
1724 "the hash of the block to reconsider"},
1725 },
1727 RPCExamples{HelpExampleCli("reconsiderblock", "\"blockhash\"") +
1728 HelpExampleRpc("reconsiderblock", "\"blockhash\"")},
1729 [&](const RPCHelpMan &self, const Config &config,
1730 const JSONRPCRequest &request) -> UniValue {
1731 NodeContext &node = EnsureAnyNodeContext(request.context);
1733 const BlockHash hash(ParseHashV(request.params[0], "blockhash"));
1734
1735 {
1736 LOCK(cs_main);
1737 CBlockIndex *pblockindex =
1738 chainman.m_blockman.LookupBlockIndex(hash);
1739 if (!pblockindex) {
1741 "Block not found");
1742 }
1743
1744 chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex);
1745 }
1746
1748 chainman.ActiveChainstate().ActivateBestChain(
1749 state, /*pblock=*/nullptr, node.avalanche.get());
1750
1751 if (!state.IsValid()) {
1753 }
1754
1755 // Block to make sure wallet/indexers sync before returning
1757
1758 return NullUniValue;
1759 },
1760 };
1761}
1762
1764 return RPCHelpMan{
1765 "unparkblock",
1766 "Removes parked status of a block and its descendants, reconsider "
1767 "them for activation.\n"
1768 "This can be used to undo the effects of parkblock.\n",
1769 {
1771 "the hash of the block to unpark"},
1772 },
1774 RPCExamples{HelpExampleCli("unparkblock", "\"blockhash\"") +
1775 HelpExampleRpc("unparkblock", "\"blockhash\"")},
1776 [&](const RPCHelpMan &self, const Config &config,
1777 const JSONRPCRequest &request) -> UniValue {
1778 const std::string strHash = request.params[0].get_str();
1779 NodeContext &node = EnsureAnyNodeContext(request.context);
1781 const BlockHash hash(uint256S(strHash));
1782 Chainstate &active_chainstate = chainman.ActiveChainstate();
1783
1784 {
1785 LOCK(cs_main);
1786
1787 CBlockIndex *pblockindex =
1788 chainman.m_blockman.LookupBlockIndex(hash);
1789 if (!pblockindex) {
1791 "Block not found");
1792 }
1793
1794 if (!pblockindex->nStatus.isOnParkedChain()) {
1795 // Block to unpark is not parked so there is nothing to do.
1796 return NullUniValue;
1797 }
1798
1799 const CBlockIndex *tip = active_chainstate.m_chain.Tip();
1800 if (tip) {
1801 const CBlockIndex *ancestor =
1802 LastCommonAncestor(tip, pblockindex);
1803 if (active_chainstate.IsBlockAvalancheFinalized(ancestor)) {
1804 // Only reset avalanche finalization if we unpark a
1805 // block that might conflict with avalanche finalized
1806 // blocks.
1807 active_chainstate.ClearAvalancheFinalizedBlock();
1808 }
1809 }
1810
1811 active_chainstate.UnparkBlockAndChildren(pblockindex);
1812 }
1813
1815 active_chainstate.ActivateBestChain(state, /*pblock=*/nullptr,
1816 node.avalanche.get());
1817
1818 if (!state.IsValid()) {
1820 }
1821
1822 // Block to make sure wallet/indexers sync before returning
1824
1825 return NullUniValue;
1826 },
1827 };
1828}
1829
1831 return RPCHelpMan{
1832 "getchaintxstats",
1833 "Compute statistics about the total number and rate of transactions "
1834 "in the chain.\n",
1835 {
1836 {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{"one month"},
1837 "Size of the window in number of blocks"},
1838 {"blockhash", RPCArg::Type::STR_HEX,
1839 RPCArg::DefaultHint{"chain tip"},
1840 "The hash of the block that ends the window."},
1841 },
1843 "",
1844 "",
1845 {
1847 "The timestamp for the final block in the window, "
1848 "expressed in " +
1850 {RPCResult::Type::NUM, "txcount",
1851 "The total number of transactions in the chain up to "
1852 "that point"},
1853 {RPCResult::Type::STR_HEX, "window_final_block_hash",
1854 "The hash of the final block in the window"},
1855 {RPCResult::Type::NUM, "window_final_block_height",
1856 "The height of the final block in the window."},
1857 {RPCResult::Type::NUM, "window_block_count",
1858 "Size of the window in number of blocks"},
1859 {RPCResult::Type::NUM, "window_tx_count",
1860 "The number of transactions in the window. Only "
1861 "returned if \"window_block_count\" is > 0"},
1862 {RPCResult::Type::NUM, "window_interval",
1863 "The elapsed time in the window in seconds. Only "
1864 "returned if \"window_block_count\" is > 0"},
1865 {RPCResult::Type::NUM, "txrate",
1866 "The average rate of transactions per second in the "
1867 "window. Only returned if \"window_interval\" is > 0"},
1868 }},
1869 RPCExamples{HelpExampleCli("getchaintxstats", "") +
1870 HelpExampleRpc("getchaintxstats", "2016")},
1871 [&](const RPCHelpMan &self, const Config &config,
1872 const JSONRPCRequest &request) -> UniValue {
1873 ChainstateManager &chainman = EnsureAnyChainman(request.context);
1874 const CBlockIndex *pindex;
1875
1876 // By default: 1 month
1877 int blockcount =
1878 30 * 24 * 60 * 60 /
1879 config.GetChainParams().GetConsensus().nPowTargetSpacing;
1880
1881 if (request.params[1].isNull()) {
1882 LOCK(cs_main);
1883 pindex = chainman.ActiveTip();
1884 } else {
1885 BlockHash hash(ParseHashV(request.params[1], "blockhash"));
1886 LOCK(cs_main);
1887 pindex = chainman.m_blockman.LookupBlockIndex(hash);
1888 if (!pindex) {
1890 "Block not found");
1891 }
1892 if (!chainman.ActiveChain().Contains(pindex)) {
1894 "Block is not in main chain");
1895 }
1896 }
1897
1898 CHECK_NONFATAL(pindex != nullptr);
1899
1900 if (request.params[0].isNull()) {
1901 blockcount =
1902 std::max(0, std::min(blockcount, pindex->nHeight - 1));
1903 } else {
1904 blockcount = request.params[0].getInt<int>();
1905
1906 if (blockcount < 0 ||
1907 (blockcount > 0 && blockcount >= pindex->nHeight)) {
1909 "Invalid block count: "
1910 "should be between 0 and "
1911 "the block's height - 1");
1912 }
1913 }
1914
1915 const CBlockIndex &past_block{*CHECK_NONFATAL(
1916 pindex->GetAncestor(pindex->nHeight - blockcount))};
1917 const int64_t nTimeDiff{pindex->GetMedianTimePast() -
1918 past_block.GetMedianTimePast()};
1919 const int nTxDiff =
1920 pindex->GetChainTxCount() - past_block.GetChainTxCount();
1921
1923 ret.pushKV("time", pindex->GetBlockTime());
1924 ret.pushKV("txcount", pindex->GetChainTxCount());
1925 ret.pushKV("window_final_block_hash",
1926 pindex->GetBlockHash().GetHex());
1927 ret.pushKV("window_final_block_height", pindex->nHeight);
1928 ret.pushKV("window_block_count", blockcount);
1929 if (blockcount > 0) {
1930 ret.pushKV("window_tx_count", nTxDiff);
1931 ret.pushKV("window_interval", nTimeDiff);
1932 if (nTimeDiff > 0) {
1933 ret.pushKV("txrate", double(nTxDiff) / nTimeDiff);
1934 }
1935 }
1936
1937 return ret;
1938 },
1939 };
1940}
1941
1942template <typename T>
1943static T CalculateTruncatedMedian(std::vector<T> &scores) {
1944 size_t size = scores.size();
1945 if (size == 0) {
1946 return T();
1947 }
1948
1949 std::sort(scores.begin(), scores.end());
1950 if (size % 2 == 0) {
1951 return (scores[size / 2 - 1] + scores[size / 2]) / 2;
1952 } else {
1953 return scores[size / 2];
1954 }
1955}
1956
1957template <typename T> static inline bool SetHasKeys(const std::set<T> &set) {
1958 return false;
1959}
1960template <typename T, typename Tk, typename... Args>
1961static inline bool SetHasKeys(const std::set<T> &set, const Tk &key,
1962 const Args &...args) {
1963 return (set.count(key) != 0) || SetHasKeys(set, args...);
1964}
1965
1966// outpoint (needed for the utxo index) + nHeight + fCoinBase
1967static constexpr size_t PER_UTXO_OVERHEAD =
1968 sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);
1969
1971 const auto &ticker = Currency::get().ticker;
1972 return RPCHelpMan{
1973 "getblockstats",
1974 "Compute per block statistics for a given window. All amounts are "
1975 "in " +
1976 ticker +
1977 ".\n"
1978 "It won't work for some heights with pruning.\n",
1979 {
1980 {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO,
1981 "The block hash or height of the target block",
1983 .type_str = {"", "string or numeric"}}},
1984 {"stats",
1986 RPCArg::DefaultHint{"all values"},
1987 "Values to plot (see result below)",
1988 {
1990 "Selected statistic"},
1992 "Selected statistic"},
1993 },
1995 },
1996 RPCResult{
1998 "",
1999 "",
2000 {
2001 {RPCResult::Type::NUM, "avgfee", "Average fee in the block"},
2002 {RPCResult::Type::NUM, "avgfeerate",
2003 "Average feerate (in satoshis per virtual byte)"},
2004 {RPCResult::Type::NUM, "avgtxsize", "Average transaction size"},
2005 {RPCResult::Type::STR_HEX, "blockhash",
2006 "The block hash (to check for potential reorgs)"},
2007 {RPCResult::Type::NUM, "height", "The height of the block"},
2008 {RPCResult::Type::NUM, "ins",
2009 "The number of inputs (excluding coinbase)"},
2010 {RPCResult::Type::NUM, "maxfee", "Maximum fee in the block"},
2011 {RPCResult::Type::NUM, "maxfeerate",
2012 "Maximum feerate (in satoshis per virtual byte)"},
2013 {RPCResult::Type::NUM, "maxtxsize", "Maximum transaction size"},
2014 {RPCResult::Type::NUM, "medianfee",
2015 "Truncated median fee in the block"},
2016 {RPCResult::Type::NUM, "medianfeerate",
2017 "Truncated median feerate (in " + ticker + " per byte)"},
2018 {RPCResult::Type::NUM, "mediantime",
2019 "The block median time past"},
2020 {RPCResult::Type::NUM, "mediantxsize",
2021 "Truncated median transaction size"},
2022 {RPCResult::Type::NUM, "minfee", "Minimum fee in the block"},
2023 {RPCResult::Type::NUM, "minfeerate",
2024 "Minimum feerate (in satoshis per virtual byte)"},
2025 {RPCResult::Type::NUM, "mintxsize", "Minimum transaction size"},
2026 {RPCResult::Type::NUM, "outs", "The number of outputs"},
2027 {RPCResult::Type::NUM, "subsidy", "The block subsidy"},
2028 {RPCResult::Type::NUM, "time", "The block time"},
2029 {RPCResult::Type::NUM, "total_out",
2030 "Total amount in all outputs (excluding coinbase and thus "
2031 "reward [ie subsidy + totalfee])"},
2032 {RPCResult::Type::NUM, "total_size",
2033 "Total size of all non-coinbase transactions"},
2034 {RPCResult::Type::NUM, "totalfee", "The fee total"},
2035 {RPCResult::Type::NUM, "txs",
2036 "The number of transactions (including coinbase)"},
2037 {RPCResult::Type::NUM, "utxo_increase",
2038 "The increase/decrease in the number of unspent outputs"},
2039 {RPCResult::Type::NUM, "utxo_size_inc",
2040 "The increase/decrease in size for the utxo index (not "
2041 "discounting op_return and similar)"},
2042 }},
2045 "getblockstats",
2046 R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
2047 HelpExampleCli("getblockstats",
2048 R"(1000 '["minfeerate","avgfeerate"]')") +
2050 "getblockstats",
2051 R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") +
2052 HelpExampleRpc("getblockstats",
2053 R"(1000, ["minfeerate","avgfeerate"])")},
2054 [&](const RPCHelpMan &self, const Config &config,
2055 const JSONRPCRequest &request) -> UniValue {
2056 ChainstateManager &chainman = EnsureAnyChainman(request.context);
2057 const CBlockIndex &pindex{*CHECK_NONFATAL(
2058 ParseHashOrHeight(request.params[0], chainman))};
2059
2060 std::set<std::string> stats;
2061 if (!request.params[1].isNull()) {
2062 const UniValue stats_univalue = request.params[1].get_array();
2063 for (unsigned int i = 0; i < stats_univalue.size(); i++) {
2064 const std::string stat = stats_univalue[i].get_str();
2065 stats.insert(stat);
2066 }
2067 }
2068
2069 const CBlock &block = GetBlockChecked(chainman.m_blockman, &pindex);
2070 const CBlockUndo &blockUndo =
2071 GetUndoChecked(chainman.m_blockman, &pindex);
2072
2073 // Calculate everything if nothing selected (default)
2074 const bool do_all = stats.size() == 0;
2075 const bool do_mediantxsize =
2076 do_all || stats.count("mediantxsize") != 0;
2077 const bool do_medianfee = do_all || stats.count("medianfee") != 0;
2078 const bool do_medianfeerate =
2079 do_all || stats.count("medianfeerate") != 0;
2080 const bool loop_inputs =
2081 do_all || do_medianfee || do_medianfeerate ||
2082 SetHasKeys(stats, "utxo_size_inc", "totalfee", "avgfee",
2083 "avgfeerate", "minfee", "maxfee", "minfeerate",
2084 "maxfeerate");
2085 const bool loop_outputs =
2086 do_all || loop_inputs || stats.count("total_out");
2087 const bool do_calculate_size =
2088 do_mediantxsize || loop_inputs ||
2089 SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize",
2090 "maxtxsize");
2091
2092 const int64_t blockMaxSize = config.GetMaxBlockSize();
2093 Amount maxfee = Amount::zero();
2094 Amount maxfeerate = Amount::zero();
2095 Amount minfee = MAX_MONEY;
2096 Amount minfeerate = MAX_MONEY;
2097 Amount total_out = Amount::zero();
2098 Amount totalfee = Amount::zero();
2099 int64_t inputs = 0;
2100 int64_t maxtxsize = 0;
2101 int64_t mintxsize = blockMaxSize;
2102 int64_t outputs = 0;
2103 int64_t total_size = 0;
2104 int64_t utxo_size_inc = 0;
2105 std::vector<Amount> fee_array;
2106 std::vector<Amount> feerate_array;
2107 std::vector<int64_t> txsize_array;
2108
2109 for (size_t i = 0; i < block.vtx.size(); ++i) {
2110 const auto &tx = block.vtx.at(i);
2111 outputs += tx->vout.size();
2112 Amount tx_total_out = Amount::zero();
2113 if (loop_outputs) {
2114 for (const CTxOut &out : tx->vout) {
2115 tx_total_out += out.nValue;
2116 utxo_size_inc +=
2119 }
2120 }
2121
2122 if (tx->IsCoinBase()) {
2123 continue;
2124 }
2125
2126 // Don't count coinbase's fake input
2127 inputs += tx->vin.size();
2128 // Don't count coinbase reward
2129 total_out += tx_total_out;
2130
2131 int64_t tx_size = 0;
2132 if (do_calculate_size) {
2133 tx_size = tx->GetTotalSize();
2134 if (do_mediantxsize) {
2135 txsize_array.push_back(tx_size);
2136 }
2137 maxtxsize = std::max(maxtxsize, tx_size);
2138 mintxsize = std::min(mintxsize, tx_size);
2139 total_size += tx_size;
2140 }
2141
2142 if (loop_inputs) {
2143 Amount tx_total_in = Amount::zero();
2144 const auto &txundo = blockUndo.vtxundo.at(i - 1);
2145 for (const Coin &coin : txundo.vprevout) {
2146 const CTxOut &prevoutput = coin.GetTxOut();
2147
2148 tx_total_in += prevoutput.nValue;
2149 utxo_size_inc -=
2150 GetSerializeSize(prevoutput, PROTOCOL_VERSION) +
2152 }
2153
2154 Amount txfee = tx_total_in - tx_total_out;
2155 CHECK_NONFATAL(MoneyRange(txfee));
2156 if (do_medianfee) {
2157 fee_array.push_back(txfee);
2158 }
2159 maxfee = std::max(maxfee, txfee);
2160 minfee = std::min(minfee, txfee);
2161 totalfee += txfee;
2162
2163 Amount feerate = txfee / tx_size;
2164 if (do_medianfeerate) {
2165 feerate_array.push_back(feerate);
2166 }
2167 maxfeerate = std::max(maxfeerate, feerate);
2168 minfeerate = std::min(minfeerate, feerate);
2169 }
2170 }
2171
2172 UniValue ret_all(UniValue::VOBJ);
2173 ret_all.pushKV("avgfee",
2174 block.vtx.size() > 1
2175 ? (totalfee / int((block.vtx.size() - 1)))
2176 : Amount::zero());
2177 ret_all.pushKV("avgfeerate", total_size > 0
2178 ? (totalfee / total_size)
2179 : Amount::zero());
2180 ret_all.pushKV("avgtxsize",
2181 (block.vtx.size() > 1)
2182 ? total_size / (block.vtx.size() - 1)
2183 : 0);
2184 ret_all.pushKV("blockhash", pindex.GetBlockHash().GetHex());
2185 ret_all.pushKV("height", (int64_t)pindex.nHeight);
2186 ret_all.pushKV("ins", inputs);
2187 ret_all.pushKV("maxfee", maxfee);
2188 ret_all.pushKV("maxfeerate", maxfeerate);
2189 ret_all.pushKV("maxtxsize", maxtxsize);
2190 ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
2191 ret_all.pushKV("medianfeerate",
2192 CalculateTruncatedMedian(feerate_array));
2193 ret_all.pushKV("mediantime", pindex.GetMedianTimePast());
2194 ret_all.pushKV("mediantxsize",
2195 CalculateTruncatedMedian(txsize_array));
2196 ret_all.pushKV("minfee",
2197 minfee == MAX_MONEY ? Amount::zero() : minfee);
2198 ret_all.pushKV("minfeerate", minfeerate == MAX_MONEY
2199 ? Amount::zero()
2200 : minfeerate);
2201 ret_all.pushKV("mintxsize",
2202 mintxsize == blockMaxSize ? 0 : mintxsize);
2203 ret_all.pushKV("outs", outputs);
2204 ret_all.pushKV("subsidy", GetBlockSubsidy(pindex.nHeight,
2205 chainman.GetConsensus()));
2206 ret_all.pushKV("time", pindex.GetBlockTime());
2207 ret_all.pushKV("total_out", total_out);
2208 ret_all.pushKV("total_size", total_size);
2209 ret_all.pushKV("totalfee", totalfee);
2210 ret_all.pushKV("txs", (int64_t)block.vtx.size());
2211 ret_all.pushKV("utxo_increase", outputs - inputs);
2212 ret_all.pushKV("utxo_size_inc", utxo_size_inc);
2213
2214 if (do_all) {
2215 return ret_all;
2216 }
2217
2219 for (const std::string &stat : stats) {
2220 const UniValue &value = ret_all[stat];
2221 if (value.isNull()) {
2222 throw JSONRPCError(
2224 strprintf("Invalid selected statistic %s", stat));
2225 }
2226 ret.pushKV(stat, value);
2227 }
2228 return ret;
2229 },
2230 };
2231}
2232
2233namespace {
2235static bool FindScriptPubKey(std::atomic<int> &scan_progress,
2236 const std::atomic<bool> &should_abort,
2237 int64_t &count, CCoinsViewCursor *cursor,
2238 const std::set<CScript> &needles,
2239 std::map<COutPoint, Coin> &out_results,
2240 std::function<void()> &interruption_point) {
2241 scan_progress = 0;
2242 count = 0;
2243 while (cursor->Valid()) {
2244 COutPoint key;
2245 Coin coin;
2246 if (!cursor->GetKey(key) || !cursor->GetValue(coin)) {
2247 return false;
2248 }
2249 if (++count % 8192 == 0) {
2250 interruption_point();
2251 if (should_abort) {
2252 // allow to abort the scan via the abort reference
2253 return false;
2254 }
2255 }
2256 if (count % 256 == 0) {
2257 // update progress reference every 256 item
2258 const TxId &txid = key.GetTxId();
2259 uint32_t high = 0x100 * *txid.begin() + *(txid.begin() + 1);
2260 scan_progress = int(high * 100.0 / 65536.0 + 0.5);
2261 }
2262 if (needles.count(coin.GetTxOut().scriptPubKey)) {
2263 out_results.emplace(key, coin);
2264 }
2265 cursor->Next();
2266 }
2267 scan_progress = 100;
2268 return true;
2269}
2270} // namespace
2271
2273static std::atomic<int> g_scan_progress;
2274static std::atomic<bool> g_scan_in_progress;
2275static std::atomic<bool> g_should_abort_scan;
2277private:
2279
2280public:
2282
2283 bool reserve() {
2285 if (g_scan_in_progress.exchange(true)) {
2286 return false;
2287 }
2288 m_could_reserve = true;
2289 return true;
2290 }
2291
2293 if (m_could_reserve) {
2294 g_scan_in_progress = false;
2295 }
2296 }
2297};
2298
2300 const auto &ticker = Currency::get().ticker;
2301 return RPCHelpMan{
2302 "scantxoutset",
2303 "Scans the unspent transaction output set for entries that match "
2304 "certain output descriptors.\n"
2305 "Examples of output descriptors are:\n"
2306 " addr(<address>) Outputs whose scriptPubKey "
2307 "corresponds to the specified address (does not include P2PK)\n"
2308 " raw(<hex script>) Outputs whose scriptPubKey "
2309 "equals the specified hex scripts\n"
2310 " combo(<pubkey>) P2PK and P2PKH outputs for "
2311 "the given pubkey\n"
2312 " pkh(<pubkey>) P2PKH outputs for the given "
2313 "pubkey\n"
2314 " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for "
2315 "the given threshold and pubkeys\n"
2316 "\nIn the above, <pubkey> either refers to a fixed public key in "
2317 "hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
2318 "or more path elements separated by \"/\", and optionally ending in "
2319 "\"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
2320 "unhardened or hardened child keys.\n"
2321 "In the latter case, a range needs to be specified by below if "
2322 "different from 1000.\n"
2323 "For more information on output descriptors, see the documentation in "
2324 "the doc/descriptors.md file.\n",
2325 {
2327 "The action to execute\n"
2328 " \"start\" for starting a "
2329 "scan\n"
2330 " \"abort\" for aborting the "
2331 "current scan (returns true when abort was successful)\n"
2332 " \"status\" for "
2333 "progress report (in %) of the current scan"},
2334 {"scanobjects",
2337 "Array of scan objects. Required for \"start\" action\n"
2338 " Every scan object is either a "
2339 "string descriptor or an object:",
2340 {
2342 "An output descriptor"},
2343 {
2344 "",
2347 "An object with output descriptor and metadata",
2348 {
2350 "An output descriptor"},
2351 {"range", RPCArg::Type::RANGE, RPCArg::Default{1000},
2352 "The range of HD chain indexes to explore (either "
2353 "end or [begin,end])"},
2354 },
2355 },
2356 },
2357 RPCArgOptions{.oneline_description = "[scanobjects,...]"}},
2358 },
2359 {
2360 RPCResult{"When action=='abort'", RPCResult::Type::BOOL, "", ""},
2361 RPCResult{"When action=='status' and no scan is in progress",
2362 RPCResult::Type::NONE, "", ""},
2363 RPCResult{
2364 "When action=='status' and scan is in progress",
2366 "",
2367 "",
2368 {
2369 {RPCResult::Type::NUM, "progress", "The scan progress"},
2370 }},
2371 RPCResult{
2372 "When action=='start'",
2374 "",
2375 "",
2376 {
2377 {RPCResult::Type::BOOL, "success",
2378 "Whether the scan was completed"},
2379 {RPCResult::Type::NUM, "txouts",
2380 "The number of unspent transaction outputs scanned"},
2381 {RPCResult::Type::NUM, "height",
2382 "The current block height (index)"},
2383 {RPCResult::Type::STR_HEX, "bestblock",
2384 "The hash of the block at the tip of the chain"},
2386 "unspents",
2387 "",
2388 {
2390 "",
2391 "",
2392 {
2393 {RPCResult::Type::STR_HEX, "txid",
2394 "The transaction id"},
2395 {RPCResult::Type::NUM, "vout", "The vout value"},
2396 {RPCResult::Type::STR_HEX, "scriptPubKey",
2397 "The script key"},
2398 {RPCResult::Type::STR, "desc",
2399 "A specialized descriptor for the matched "
2400 "scriptPubKey"},
2401 {RPCResult::Type::STR_AMOUNT, "amount",
2402 "The total amount in " + ticker +
2403 " of the unspent output"},
2404 {RPCResult::Type::BOOL, "coinbase",
2405 "Whether this is a coinbase output"},
2406 {RPCResult::Type::NUM, "height",
2407 "Height of the unspent transaction output"},
2408 }},
2409 }},
2410 {RPCResult::Type::STR_AMOUNT, "total_amount",
2411 "The total amount of all found unspent outputs in " +
2412 ticker},
2413 }},
2414 },
2415 RPCExamples{""},
2416 [&](const RPCHelpMan &self, const Config &config,
2417 const JSONRPCRequest &request) -> UniValue {
2418 UniValue result(UniValue::VOBJ);
2419 const auto action{self.Arg<std::string>("action")};
2420 if (action == "status") {
2421 CoinsViewScanReserver reserver;
2422 if (reserver.reserve()) {
2423 // no scan in progress
2424 return NullUniValue;
2425 }
2426 result.pushKV("progress", g_scan_progress.load());
2427 return result;
2428 } else if (action == "abort") {
2429 CoinsViewScanReserver reserver;
2430 if (reserver.reserve()) {
2431 // reserve was possible which means no scan was running
2432 return false;
2433 }
2434 // set the abort flag
2435 g_should_abort_scan = true;
2436 return true;
2437 } else if (action == "start") {
2438 CoinsViewScanReserver reserver;
2439 if (!reserver.reserve()) {
2441 "Scan already in progress, use action "
2442 "\"abort\" or \"status\"");
2443 }
2444
2445 if (request.params.size() < 2) {
2447 "scanobjects argument is required for "
2448 "the start action");
2449 }
2450
2451 std::set<CScript> needles;
2452 std::map<CScript, std::string> descriptors;
2453 Amount total_in = Amount::zero();
2454
2455 // loop through the scan objects
2456 for (const UniValue &scanobject :
2457 request.params[1].get_array().getValues()) {
2458 FlatSigningProvider provider;
2459 auto scripts =
2460 EvalDescriptorStringOrObject(scanobject, provider);
2461 for (CScript &script : scripts) {
2462 std::string inferred =
2463 InferDescriptor(script, provider)->ToString();
2464 needles.emplace(script);
2465 descriptors.emplace(std::move(script),
2466 std::move(inferred));
2467 }
2468 }
2469
2470 // Scan the unspent transaction output set for inputs
2471 UniValue unspents(UniValue::VARR);
2472 std::vector<CTxOut> input_txos;
2473 std::map<COutPoint, Coin> coins;
2474 g_should_abort_scan = false;
2475 g_scan_progress = 0;
2476 int64_t count = 0;
2477 std::unique_ptr<CCoinsViewCursor> pcursor;
2478 const CBlockIndex *tip;
2479 NodeContext &node = EnsureAnyNodeContext(request.context);
2480 {
2482 LOCK(cs_main);
2483 Chainstate &active_chainstate = chainman.ActiveChainstate();
2484 active_chainstate.ForceFlushStateToDisk();
2485 pcursor = CHECK_NONFATAL(std::unique_ptr<CCoinsViewCursor>(
2486 active_chainstate.CoinsDB().Cursor()));
2487 tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
2488 }
2489 bool res = FindScriptPubKey(
2490 g_scan_progress, g_should_abort_scan, count, pcursor.get(),
2491 needles, coins, node.rpc_interruption_point);
2492 result.pushKV("success", res);
2493 result.pushKV("txouts", count);
2494 result.pushKV("height", tip->nHeight);
2495 result.pushKV("bestblock", tip->GetBlockHash().GetHex());
2496
2497 for (const auto &it : coins) {
2498 const COutPoint &outpoint = it.first;
2499 const Coin &coin = it.second;
2500 const CTxOut &txo = coin.GetTxOut();
2501 input_txos.push_back(txo);
2502 total_in += txo.nValue;
2503
2504 UniValue unspent(UniValue::VOBJ);
2505 unspent.pushKV("txid", outpoint.GetTxId().GetHex());
2506 unspent.pushKV("vout", int32_t(outpoint.GetN()));
2507 unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
2508 unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
2509 unspent.pushKV("amount", txo.nValue);
2510 unspent.pushKV("coinbase", coin.IsCoinBase());
2511 unspent.pushKV("height", int32_t(coin.GetHeight()));
2512
2513 unspents.push_back(unspent);
2514 }
2515 result.pushKV("unspents", unspents);
2516 result.pushKV("total_amount", total_in);
2517 } else {
2519 strprintf("Invalid action '%s'", action));
2520 }
2521 return result;
2522 },
2523 };
2524}
2525
2527 return RPCHelpMan{
2528 "getblockfilter",
2529 "Retrieve a BIP 157 content filter for a particular block.\n",
2530 {
2532 "The hash of the block"},
2533 {"filtertype", RPCArg::Type::STR, RPCArg::Default{"basic"},
2534 "The type name of the filter"},
2535 },
2537 "",
2538 "",
2539 {
2540 {RPCResult::Type::STR_HEX, "filter",
2541 "the hex-encoded filter data"},
2542 {RPCResult::Type::STR_HEX, "header",
2543 "the hex-encoded filter header"},
2544 }},
2546 HelpExampleCli("getblockfilter",
2547 "\"00000000c937983704a73af28acdec37b049d214a"
2548 "dbda81d7e2a3dd146f6ed09\" \"basic\"") +
2549 HelpExampleRpc("getblockfilter",
2550 "\"00000000c937983704a73af28acdec37b049d214adbda81d7"
2551 "e2a3dd146f6ed09\", \"basic\"")},
2552 [&](const RPCHelpMan &self, const Config &config,
2553 const JSONRPCRequest &request) -> UniValue {
2554 const BlockHash block_hash(
2555 ParseHashV(request.params[0], "blockhash"));
2556 std::string filtertype_name = "basic";
2557 if (!request.params[1].isNull()) {
2558 filtertype_name = request.params[1].get_str();
2559 }
2560
2561 BlockFilterType filtertype;
2562 if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2564 "Unknown filtertype");
2565 }
2566
2567 BlockFilterIndex *index = GetBlockFilterIndex(filtertype);
2568 if (!index) {
2570 "Index is not enabled for filtertype " +
2571 filtertype_name);
2572 }
2573
2574 const CBlockIndex *block_index;
2575 bool block_was_connected;
2576 {
2577 ChainstateManager &chainman =
2578 EnsureAnyChainman(request.context);
2579 LOCK(cs_main);
2580 block_index = chainman.m_blockman.LookupBlockIndex(block_hash);
2581 if (!block_index) {
2583 "Block not found");
2584 }
2585 block_was_connected =
2586 block_index->IsValid(BlockValidity::SCRIPTS);
2587 }
2588
2589 bool index_ready = index->BlockUntilSyncedToCurrentChain();
2590
2591 BlockFilter filter;
2592 uint256 filter_header;
2593 if (!index->LookupFilter(block_index, filter) ||
2594 !index->LookupFilterHeader(block_index, filter_header)) {
2595 int err_code;
2596 std::string errmsg = "Filter not found.";
2597
2598 if (!block_was_connected) {
2599 err_code = RPC_INVALID_ADDRESS_OR_KEY;
2600 errmsg += " Block was not connected to active chain.";
2601 } else if (!index_ready) {
2602 err_code = RPC_MISC_ERROR;
2603 errmsg += " Block filters are still in the process of "
2604 "being indexed.";
2605 } else {
2606 err_code = RPC_INTERNAL_ERROR;
2607 errmsg += " This error is unexpected and indicates index "
2608 "corruption.";
2609 }
2610
2611 throw JSONRPCError(err_code, errmsg);
2612 }
2613
2615 ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
2616 ret.pushKV("header", filter_header.GetHex());
2617 return ret;
2618 },
2619 };
2620}
2621
2628 return RPCHelpMan{
2629 "dumptxoutset",
2630 "Write the serialized UTXO set to a file.\n",
2631 {
2633 "path to the output file. If relative, will be prefixed by "
2634 "datadir."},
2635 },
2637 "",
2638 "",
2639 {
2640 {RPCResult::Type::NUM, "coins_written",
2641 "the number of coins written in the snapshot"},
2642 {RPCResult::Type::STR_HEX, "base_hash",
2643 "the hash of the base of the snapshot"},
2644 {RPCResult::Type::NUM, "base_height",
2645 "the height of the base of the snapshot"},
2646 {RPCResult::Type::STR, "path",
2647 "the absolute path that the snapshot was written to"},
2648 {RPCResult::Type::STR_HEX, "txoutset_hash",
2649 "the hash of the UTXO set contents"},
2650 {RPCResult::Type::NUM, "nchaintx",
2651 "the number of transactions in the chain up to and "
2652 "including the base block"},
2653 }},
2654 RPCExamples{HelpExampleCli("dumptxoutset", "utxo.dat")},
2655 [&](const RPCHelpMan &self, const Config &config,
2656 const JSONRPCRequest &request) -> UniValue {
2657 const ArgsManager &args{EnsureAnyArgsman(request.context)};
2658 const fs::path path = fsbridge::AbsPathJoin(
2659 args.GetDataDirNet(), fs::u8path(request.params[0].get_str()));
2660 // Write to a temporary path and then move into `path` on completion
2661 // to avoid confusion due to an interruption.
2662 const fs::path temppath = fsbridge::AbsPathJoin(
2663 args.GetDataDirNet(),
2664 fs::u8path(request.params[0].get_str() + ".incomplete"));
2665
2666 if (fs::exists(path)) {
2668 path.u8string() +
2669 " already exists. If you are sure this "
2670 "is what you want, "
2671 "move it out of the way first");
2672 }
2673
2674 FILE *file{fsbridge::fopen(temppath, "wb")};
2675 AutoFile afile{file};
2676 NodeContext &node = EnsureAnyNodeContext(request.context);
2678 node, node.chainman->ActiveChainstate(), afile, path, temppath);
2679 fs::rename(temppath, path);
2680
2681 return result;
2682 },
2683 };
2684}
2685
2687 AutoFile &afile, const fs::path &path,
2688 const fs::path &temppath) {
2689 std::unique_ptr<CCoinsViewCursor> pcursor;
2690 std::optional<CCoinsStats> maybe_stats;
2691 const CBlockIndex *tip;
2692
2693 {
2694 // We need to lock cs_main to ensure that the coinsdb isn't
2695 // written to between (i) flushing coins cache to disk
2696 // (coinsdb), (ii) getting stats based upon the coinsdb, and
2697 // (iii) constructing a cursor to the coinsdb for use below this
2698 // block.
2699 //
2700 // Cursors returned by leveldb iterate over snapshots, so the
2701 // contents of the pcursor will not be affected by simultaneous
2702 // writes during use below this block.
2703 //
2704 // See discussion here:
2705 // https://github.com/bitcoin/bitcoin/pull/15606#discussion_r274479369
2706 //
2707 LOCK(::cs_main);
2708
2709 chainstate.ForceFlushStateToDisk();
2710
2711 maybe_stats = GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman,
2712 CoinStatsHashType::HASH_SERIALIZED,
2713 node.rpc_interruption_point);
2714 if (!maybe_stats) {
2715 throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
2716 }
2717
2718 pcursor =
2719 std::unique_ptr<CCoinsViewCursor>(chainstate.CoinsDB().Cursor());
2720 tip = CHECK_NONFATAL(
2721 chainstate.m_blockman.LookupBlockIndex(maybe_stats->hashBlock));
2722 }
2723
2725 strprintf("writing UTXO snapshot at height %s (%s) to file %s (via %s)",
2726 tip->nHeight, tip->GetBlockHash().ToString(),
2727 fs::PathToString(path), fs::PathToString(temppath)));
2728
2729 SnapshotMetadata metadata{tip->GetBlockHash(), maybe_stats->coins_count};
2730
2731 afile << metadata;
2732
2733 COutPoint key;
2734 TxId last_txid;
2735 Coin coin;
2736 unsigned int iter{0};
2737 size_t written_coins_count{0};
2738 std::vector<std::pair<uint32_t, Coin>> coins;
2739
2740 // To reduce space the serialization format of the snapshot avoids
2741 // duplication of tx hashes. The code takes advantage of the guarantee by
2742 // leveldb that keys are lexicographically sorted.
2743 // In the coins vector we collect all coins that belong to a certain tx hash
2744 // (key.hash) and when we have them all (key.hash != last_hash) we write
2745 // them to file using the below lambda function.
2746 // See also https://github.com/bitcoin/bitcoin/issues/25675
2747 auto write_coins_to_file =
2748 [&](AutoFile &afile, const TxId &last_txid,
2749 const std::vector<std::pair<uint32_t, Coin>> &coins,
2750 size_t &written_coins_count) {
2751 afile << last_txid;
2752 WriteCompactSize(afile, coins.size());
2753 for (const auto &[n, coin_] : coins) {
2754 WriteCompactSize(afile, n);
2755 afile << coin_;
2756 ++written_coins_count;
2757 }
2758 };
2759
2760 pcursor->GetKey(key);
2761 last_txid = key.GetTxId();
2762 while (pcursor->Valid()) {
2763 if (iter % 5000 == 0) {
2764 node.rpc_interruption_point();
2765 }
2766 ++iter;
2767 if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
2768 if (key.GetTxId() != last_txid) {
2769 write_coins_to_file(afile, last_txid, coins,
2770 written_coins_count);
2771 last_txid = key.GetTxId();
2772 coins.clear();
2773 }
2774 coins.emplace_back(key.GetN(), coin);
2775 }
2776 pcursor->Next();
2777 }
2778
2779 if (!coins.empty()) {
2780 write_coins_to_file(afile, last_txid, coins, written_coins_count);
2781 }
2782
2783 CHECK_NONFATAL(written_coins_count == maybe_stats->coins_count);
2784
2785 afile.fclose();
2786
2787 UniValue result(UniValue::VOBJ);
2788 result.pushKV("coins_written", written_coins_count);
2789 result.pushKV("base_hash", tip->GetBlockHash().ToString());
2790 result.pushKV("base_height", tip->nHeight);
2791 result.pushKV("path", path.u8string());
2792 result.pushKV("txoutset_hash", maybe_stats->hashSerialized.ToString());
2793 result.pushKV("nchaintx", tip->nChainTx);
2794 return result;
2795}
2796
2798 return RPCHelpMan{
2799 "loadtxoutset",
2800 "Load the serialized UTXO set from a file.\n"
2801 "Once this snapshot is loaded, its contents will be deserialized into "
2802 "a second chainstate data structure, which is then used to sync to the "
2803 "network's tip. "
2804 "Meanwhile, the original chainstate will complete the initial block "
2805 "download process in the background, eventually validating up to the "
2806 "block that the snapshot is based upon.\n\n"
2807 "The result is a usable bitcoind instance that is current with the "
2808 "network tip in a matter of minutes rather than hours. UTXO snapshot "
2809 "are typically obtained from third-party sources (HTTP, torrent, etc.) "
2810 "which is reasonable since their contents are always checked by "
2811 "hash.\n\n"
2812 "You can find more information on this process in the `assumeutxo` "
2813 "design document (https://www.bitcoinabc.org/doc/assumeutxo.html).",
2814 {
2816 "path to the snapshot file. If relative, will be prefixed by "
2817 "datadir."},
2818 },
2820 "",
2821 "",
2822 {
2823 {RPCResult::Type::NUM, "coins_loaded",
2824 "the number of coins loaded from the snapshot"},
2825 {RPCResult::Type::STR_HEX, "tip_hash",
2826 "the hash of the base of the snapshot"},
2827 {RPCResult::Type::NUM, "base_height",
2828 "the height of the base of the snapshot"},
2829 {RPCResult::Type::STR, "path",
2830 "the absolute path that the snapshot was loaded from"},
2831 }},
2832 RPCExamples{HelpExampleCli("loadtxoutset", "utxo.dat")},
2833 [&](const RPCHelpMan &self, const Config &config,
2834 const JSONRPCRequest &request) -> UniValue {
2835 NodeContext &node = EnsureAnyNodeContext(request.context);
2838 EnsureArgsman(node), fs::u8path(request.params[0].get_str()))};
2839
2840 FILE *file{fsbridge::fopen(path, "rb")};
2841 AutoFile afile{file};
2842 if (afile.IsNull()) {
2844 "Couldn't open file " + path.u8string() +
2845 " for reading.");
2846 }
2847
2848 SnapshotMetadata metadata;
2849 afile >> metadata;
2850
2851 BlockHash base_blockhash = metadata.m_base_blockhash;
2852 if (!chainman.GetParams()
2853 .AssumeutxoForBlockhash(base_blockhash)
2854 .has_value()) {
2855 throw JSONRPCError(
2857 strprintf("Unable to load UTXO snapshot, "
2858 "assumeutxo block hash in snapshot metadata not "
2859 "recognized (%s)",
2860 base_blockhash.ToString()));
2861 }
2862 CBlockIndex *snapshot_start_block = WITH_LOCK(
2863 ::cs_main,
2864 return chainman.m_blockman.LookupBlockIndex(base_blockhash));
2865
2866 if (!snapshot_start_block) {
2867 throw JSONRPCError(
2869 strprintf("The base block header (%s) must appear in the "
2870 "headers chain. Make sure all headers are "
2871 "synced, and call this RPC again.",
2872 base_blockhash.ToString()));
2873 }
2874 if (!chainman.ActivateSnapshot(afile, metadata, false)) {
2876 "Unable to load UTXO snapshot " +
2877 fs::PathToString(path));
2878 }
2879
2880 // Because we can't provide historical blocks during tip or
2881 // background sync. Update local services to reflect we are a
2882 // limited peer until we are fully sync.
2883 node.connman->RemoveLocalServices(NODE_NETWORK);
2884 // Setting the limited state is usually redundant because the node
2885 // can always provide the last 288 blocks, but it doesn't hurt to
2886 // set it.
2887 node.connman->AddLocalServices(NODE_NETWORK_LIMITED);
2888
2889 CBlockIndex *new_tip{
2890 WITH_LOCK(::cs_main, return chainman.ActiveTip())};
2891
2892 UniValue result(UniValue::VOBJ);
2893 result.pushKV("coins_loaded", metadata.m_coins_count);
2894 result.pushKV("tip_hash", new_tip->GetBlockHash().ToString());
2895 result.pushKV("base_height", new_tip->nHeight);
2896 result.pushKV("path", fs::PathToString(path));
2897 return result;
2898 },
2899 };
2900}
2901
2902const std::vector<RPCResult> RPCHelpForChainstate{
2903 {RPCResult::Type::NUM, "blocks", "number of blocks in this chainstate"},
2904 {RPCResult::Type::STR_HEX, "bestblockhash", "blockhash of the tip"},
2905 {RPCResult::Type::NUM, "difficulty", "difficulty of the tip"},
2906 {RPCResult::Type::NUM, "verificationprogress",
2907 "progress towards the network tip"},
2908 {RPCResult::Type::STR_HEX, "snapshot_blockhash", /*optional=*/true,
2909 "the base block of the snapshot this chainstate is based on, if any"},
2910 {RPCResult::Type::NUM, "coins_db_cache_bytes", "size of the coinsdb cache"},
2911 {RPCResult::Type::NUM, "coins_tip_cache_bytes",
2912 "size of the coinstip cache"},
2913 {RPCResult::Type::BOOL, "validated",
2914 "whether the chainstate is fully validated. True if all blocks in the "
2915 "chainstate were validated, false if the chain is based on a snapshot and "
2916 "the snapshot has not yet been validated."},
2917
2918};
2919
2921 return RPCHelpMan{
2922 "getchainstates",
2923 "\nReturn information about chainstates.\n",
2924 {},
2926 "",
2927 "",
2928 {
2929 {RPCResult::Type::NUM, "headers",
2930 "the number of headers seen so far"},
2932 "chainstates",
2933 "list of the chainstates ordered by work, with the "
2934 "most-work (active) chainstate last",
2935 {
2937 }},
2938 }},
2939 RPCExamples{HelpExampleCli("getchainstates", "") +
2940 HelpExampleRpc("getchainstates", "")},
2941 [&](const RPCHelpMan &self, const Config &config,
2942 const JSONRPCRequest &request) -> UniValue {
2943 LOCK(cs_main);
2945
2946 ChainstateManager &chainman = EnsureAnyChainman(request.context);
2947
2948 auto make_chain_data =
2949 [&](const Chainstate &chainstate,
2950 bool validated) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
2953 if (!chainstate.m_chain.Tip()) {
2954 return data;
2955 }
2956 const CChain &chain = chainstate.m_chain;
2957 const CBlockIndex *tip = chain.Tip();
2958
2959 data.pushKV("blocks", chain.Height());
2960 data.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
2961 data.pushKV("difficulty", GetDifficulty(tip));
2962 data.pushKV(
2963 "verificationprogress",
2964 GuessVerificationProgress(Params().TxData(), tip));
2965 data.pushKV("coins_db_cache_bytes",
2966 chainstate.m_coinsdb_cache_size_bytes);
2967 data.pushKV("coins_tip_cache_bytes",
2968 chainstate.m_coinstip_cache_size_bytes);
2969 if (chainstate.m_from_snapshot_blockhash) {
2970 data.pushKV(
2971 "snapshot_blockhash",
2972 chainstate.m_from_snapshot_blockhash->ToString());
2973 }
2974 data.pushKV("validated", validated);
2975 return data;
2976 };
2977
2978 obj.pushKV("headers", chainman.m_best_header
2979 ? chainman.m_best_header->nHeight
2980 : -1);
2981
2982 const auto &chainstates = chainman.GetAll();
2983 UniValue obj_chainstates{UniValue::VARR};
2984 for (Chainstate *cs : chainstates) {
2985 obj_chainstates.push_back(
2986 make_chain_data(*cs, !cs->m_from_snapshot_blockhash ||
2987 chainstates.size() == 1));
2988 }
2989 obj.pushKV("chainstates", std::move(obj_chainstates));
2990 return obj;
2991 }};
2992}
2993
2995 // clang-format off
2996 static const CRPCCommand commands[] = {
2997 // category actor (function)
2998 // ------------------ ----------------------
2999 { "blockchain", getbestblockhash, },
3000 { "blockchain", getblock, },
3001 { "blockchain", getblockfrompeer, },
3002 { "blockchain", getblockchaininfo, },
3003 { "blockchain", getblockcount, },
3004 { "blockchain", getblockhash, },
3005 { "blockchain", getblockheader, },
3006 { "blockchain", getblockstats, },
3007 { "blockchain", getchaintips, },
3008 { "blockchain", getchaintxstats, },
3009 { "blockchain", getdifficulty, },
3010 { "blockchain", gettxout, },
3011 { "blockchain", gettxoutsetinfo, },
3012 { "blockchain", pruneblockchain, },
3013 { "blockchain", verifychain, },
3014 { "blockchain", preciousblock, },
3015 { "blockchain", scantxoutset, },
3016 { "blockchain", getblockfilter, },
3017 { "blockchain", dumptxoutset, },
3018 { "blockchain", loadtxoutset, },
3019 { "blockchain", getchainstates, },
3020
3021 /* Not shown in help */
3022 { "hidden", invalidateblock, },
3023 { "hidden", parkblock, },
3024 { "hidden", reconsiderblock, },
3025 { "hidden", syncwithvalidationinterfacequeue, },
3026 { "hidden", unparkblock, },
3027 { "hidden", waitfornewblock, },
3028 { "hidden", waitforblock, },
3029 { "hidden", waitforblockheight, },
3030 };
3031 // clang-format on
3032 for (const auto &c : commands) {
3033 t.appendCommand(c.name, &c);
3034 }
3035}
bool MoneyRange(const Amount nValue)
Definition: amount.h:166
static constexpr Amount MAX_MONEY
No amount larger than this (in satoshi) is valid.
Definition: amount.h:165
fs::path AbsPathForConfigVal(const ArgsManager &args, const fs::path &path, bool net_specific=true)
Most paths passed as configuration arguments are treated as relative to the datadir if they are not a...
Definition: configfile.cpp:236
RPCHelpMan gettxout()
static RPCHelpMan getblock()
Definition: blockchain.cpp:681
static int ComputeNextBlockAndDepth(const CBlockIndex *tip, const CBlockIndex *blockindex, const CBlockIndex *&next)
Definition: blockchain.cpp:90
static RPCHelpMan getdifficulty()
Definition: blockchain.cpp:441
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:424
static RPCHelpMan getchaintips()
static RPCHelpMan loadtxoutset()
static RPCHelpMan gettxoutsetinfo()
Definition: blockchain.cpp:946
static RPCHelpMan getchainstates()
static RPCHelpMan getblockstats()
static CoinStatsHashType ParseHashType(const std::string &hash_type_input)
Definition: blockchain.cpp:932
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:72
static RPCHelpMan scantxoutset()
static std::condition_variable cond_blockchange
Definition: blockchain.cpp:66
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:662
std::optional< int > GetPruneHeight(const BlockManager &blockman, const CChain &chain)
Definition: blockchain.cpp:820
static RPCHelpMan getblockfilter()
static RPCHelpMan getbestblockhash()
Definition: blockchain.cpp:218
static CBlock GetBlockChecked(BlockManager &blockman, const CBlockIndex *pblockindex)
Definition: blockchain.cpp:640
RPCHelpMan getblockchaininfo()
UniValue blockToJSON(BlockManager &blockman, const CBlock &block, const CBlockIndex *tip, const CBlockIndex *blockindex, bool txDetails)
Block description to JSON.
Definition: blockchain.cpp:167
static RPCHelpMan getchaintxstats()
static RPCHelpMan waitforblock()
Definition: blockchain.cpp:302
static RPCHelpMan getblockfrompeer()
Definition: blockchain.cpp:461
static RPCHelpMan getblockhash()
Definition: blockchain.cpp:515
void RegisterBlockchainRPCCommands(CRPCTable &t)
static RPCHelpMan verifychain()
static std::atomic< bool > g_should_abort_scan
const std::vector< RPCResult > RPCHelpForChainstate
RPCHelpMan unparkblock()
UniValue blockheaderToJSON(const CBlockIndex *tip, const CBlockIndex *blockindex)
Block header to JSON.
Definition: blockchain.cpp:133
static RPCHelpMan waitforblockheight()
Definition: blockchain.cpp:364
static const CBlockIndex * ParseHashOrHeight(const UniValue &param, ChainstateManager &chainman)
Definition: blockchain.cpp:101
static RPCHelpMan pruneblockchain()
Definition: blockchain.cpp:858
static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange)
static RPCHelpMan getblockheader()
Definition: blockchain.cpp:544
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:65
static RPCHelpMan dumptxoutset()
Serialize the UTXO set to a file for loading elsewhere.
static RPCHelpMan getblockcount()
Definition: blockchain.cpp:200
static RPCHelpMan waitfornewblock()
Definition: blockchain.cpp:245
void RPCNotifyBlockChange(const CBlockIndex *pindex)
Callback for when block tip changed.
Definition: blockchain.cpp:236
bool BlockFilterTypeByName(const std::string &name, BlockFilterType &filter_type)
Find a filter type by its human-readable name.
BlockFilterType
Definition: blockfilter.h:88
BlockFilterIndex * GetBlockFilterIndex(BlockFilterType filter_type)
Get a block filter index by type.
@ SCRIPTS
Scripts & signatures ok.
@ TREE
All parent headers found, difficulty matches, timestamp >= median previous, checkpoint.
const CBlockIndex * LastCommonAncestor(const CBlockIndex *pa, const CBlockIndex *pb)
Find the last common ancestor two blocks have.
Definition: chain.cpp:112
static constexpr int64_t TIMESTAMP_WINDOW
Timestamp window used as a grace period by code that compares external timestamps (such as timestamps...
Definition: chain.h:36
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:19
#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:191
uint256 hashMerkleRoot
Definition: blockindex.h:75
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: blockindex.h:32
CBlockHeader GetBlockHeader() const
Definition: blockindex.h:117
arith_uint256 nChainWork
(memory only) Total amount of work (expected number of hashes) in the chain up to and including this ...
Definition: blockindex.h:51
int64_t GetChainTxCount() const
Get the number of transaction in the chain so far.
Definition: blockindex.h:138
uint32_t nTime
Definition: blockindex.h:76
uint32_t nNonce
Definition: blockindex.h:78
int64_t GetBlockTime() const
Definition: blockindex.h:160
int64_t GetMedianTimePast() const
Definition: blockindex.h:172
uint32_t nBits
Definition: blockindex.h:77
unsigned int nTx
Number of transactions in this block.
Definition: blockindex.h:55
int32_t nVersion
block header
Definition: blockindex.h:74
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition: blockindex.cpp:62
BlockHash GetBlockHash() const
Definition: blockindex.h:130
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: blockindex.h:38
unsigned int nChainTx
(memory only) Number of transactions in the chain up to and including this block.
Definition: blockindex.h:68
Undo information for a CBlock.
Definition: undo.h:73
std::vector< CTxUndo > vtxundo
Definition: undo.h:76
An in-memory indexed chain of blocks.
Definition: chain.h:134
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:150
CBlockIndex * FindEarliestAtLeast(int64_t nTime, int height) const
Find the earliest block with timestamp equal or greater than the given time and height equal or great...
Definition: chain.cpp:62
int Height() const
Return the maximal height in the chain.
Definition: chain.h:186
const CBlockIndex * FindFork(const CBlockIndex *pindex) const
Find the last common block between this chain and a block index entry.
Definition: chain.cpp:49
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
Definition: chain.h:166
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
Definition: chainparams.h:85
std::string NetworkIDString() const
Return the BIP70 network string (main, test or regtest)
Definition: chainparams.h:132
const ChainTxData & TxData() const
Definition: chainparams.h:152
std::optional< AssumeutxoData > AssumeutxoForBlockhash(const BlockHash &blockhash) const
Definition: chainparams.h:146
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:221
BlockHash GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:214
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: coins.cpp:95
Cursor for iterating over CoinsView state.
Definition: coins.h:143
virtual void Next()=0
virtual bool Valid() const =0
virtual bool GetKey(COutPoint &key) const =0
virtual bool GetValue(Coin &coin) const =0
CCoinsViewCursor * Cursor() const override
Get a cursor to iterate over the whole state.
Definition: txdb.cpp:208
Abstract view on the open txout dataset.
Definition: coins.h:163
virtual BlockHash GetBestBlock() const
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:16
CCoinsView that brings transactions from a mempool into view.
Definition: txmempool.h:635
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
GetCoin, returning whether it exists and is not spent.
Definition: txmempool.cpp:705
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:177
RPC command dispatcher.
Definition: server.h:194
void appendCommand(const std::string &name, const CRPCCommand *pcmd)
Appends a CRPCCommand to the dispatch table.
Definition: server.cpp:327
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:214
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:310
bool isSpent(const COutPoint &outpoint) const
Definition: txmempool.cpp:135
An output of a transaction.
Definition: transaction.h:128
CScript scriptPubKey
Definition: transaction.h:131
Amount nValue
Definition: transaction.h:130
Restore the UTXO in a Coin at a given COutPoint.
Definition: undo.h:62
RAII wrapper for VerifyDB: Verify consistency of the block and coin databases.
Definition: validation.h:621
VerifyDBResult VerifyDB(Chainstate &chainstate, CCoinsView &coinsview, int nCheckLevel, int nCheckDepth) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Definition: validation.h:700
bool IsBlockAvalancheFinalized(const CBlockIndex *pindex) const EXCLUSIVE_LOCKS_REQUIRED(!cs_avalancheFinalizedBlockIndex)
Checks if a block is finalized by avalanche voting.
const std::optional< BlockHash > m_from_snapshot_blockhash
The blockhash which is the base of the snapshot this chainstate was created from.
Definition: validation.h:807
bool ActivateBestChain(BlockValidationState &state, std::shared_ptr< const CBlock > pblock=nullptr, avalanche::Processor *const avalanche=nullptr) EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex
Find the best known block, and make it the tip of the block chain.
CChain m_chain
The current chain of blockheaders we consult and build on.
Definition: validation.h:799
size_t m_coinstip_cache_size_bytes
The cache size of the in-memory coins view.
Definition: validation.h:859
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:826
size_t m_coinsdb_cache_size_bytes
The cache size of the on-disk coins view.
Definition: validation.h:856
void ForceFlushStateToDisk()
Unconditionally flush all changes to disk.
void UnparkBlockAndChildren(CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Remove parked status from a block and its descendants.
CCoinsViewDB & CoinsDB() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:833
node::BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all Chainstate instances.
Definition: validation.h:757
void ClearAvalancheFinalizedBlock() EXCLUSIVE_LOCKS_REQUIRED(!cs_avalancheFinalizedBlockIndex)
Clear avalanche finalization.
bool ParkBlock(BlockValidationState &state, CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex
Park a block.
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:1149
node::BlockMap & BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:1421
SnapshotCompletionResult MaybeCompleteSnapshotValidation(std::function< void(bilingual_str)> shutdown_fnc=[](bilingual_str msg) { AbortNode(msg.original, msg);}) EXCLUSIVE_LOCKS_REQUIRED(const CBlockIndex *GetSnapshotBaseBlock() const EXCLUSIVE_LOCKS_REQUIRED(Chainstate ActiveChainstate)() const
Once the background validation chainstate has reached the height which is the base of the UTXO snapsh...
Definition: validation.h:1397
kernel::Notifications & GetNotifications() const
Definition: validation.h:1256
bool IsInitialBlockDownload() const
Check whether we are doing an initial block download (synchronizing from disk or network)
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1404
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1401
bool ActivateSnapshot(AutoFile &coins_file, const node::SnapshotMetadata &metadata, bool in_memory)
Construct and activate a Chainstate on the basis of UTXO snapshot data.
const CChainParams & GetParams() const
Definition: validation.h:1241
const Consensus::Params & GetConsensus() const
Definition: validation.h:1244
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1398
Chainstate &InitializeChainstate(CTxMemPool *mempool) EXCLUSIVE_LOCKS_REQUIRED(std::vector< Chainstate * GetAll)()
Instantiate a new chainstate.
Definition: validation.h:1361
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1287
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.
auto Arg(size_t i) const
Helper to get a required or default-valued request argument.
Definition: util.h:410
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:104
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:320
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:317
Metadata describing a serialized version of a UTXO set from which an assumeutxo Chainstate can be con...
Definition: utxo_snapshot.h:21
uint64_t m_coins_count
The number of coins in the UTXO set contained in this snapshot.
Definition: utxo_snapshot.h:29
BlockHash m_base_blockhash
The hash of the block that reflects the tip of the chain for the UTXO set contained in this snapshot.
Definition: utxo_snapshot.h:25
256-bit opaque blob.
Definition: uint256.h:129
std::unique_ptr< CoinStatsIndex > g_coin_stats_index
The global UTXO set hash object.
void TxToUniv(const CTransaction &tx, const BlockHash &hashBlock, UniValue &entry, bool include_hex=true, int serialize_flags=0, const CTxUndo *txundo=nullptr)
Definition: core_write.cpp:217
void ScriptPubKeyToUniv(const CScript &scriptPubKey, UniValue &out, bool fIncludeHex)
Definition: core_write.cpp:190
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:7
std::unique_ptr< Descriptor > InferDescriptor(const CScript &script, const SigningProvider &provider)
Find a descriptor for the specified script, using information from provider where possible.
#define LogPrint(category,...)
Definition: logging.h:238
unsigned int nHeight
static void pool cs
@ RPC
Definition: logging.h:47
@ NONE
Definition: logging.h:39
static path u8path(const std::string &utf8_str)
Definition: fs.h:90
static bool exists(const path &p)
Definition: fs.h:102
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition: fs.h:142
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:30
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:39
CoinStatsHashType
Definition: coinstats.h:23
Definition: init.h:31
std::optional< kernel::CCoinsStats > GetUTXOStats(CCoinsView *view, BlockManager &blockman, kernel::CoinStatsHashType hash_type, const std::function< void()> &interruption_point, const CBlockIndex *pindex, bool index_requested)
Calculate statistics about the unspent transaction output set.
Definition: coinstats.cpp:16
int64_t NodeId
Definition: nodeid.h:10
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:315
@ NODE_NETWORK_LIMITED
Definition: protocol.h:365
@ NODE_NETWORK
Definition: protocol.h:342
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:58
@ RPC_MISC_ERROR
General application defined errors std::exception thrown in command handling.
Definition: protocol.h:38
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:46
@ RPC_INTERNAL_ERROR
Definition: protocol.h:33
@ RPC_DATABASE_ERROR
Database error.
Definition: protocol.h:48
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:42
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:153
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:170
std::vector< CScript > EvalDescriptorStringOrObject(const UniValue &scanobject, FlatSigningProvider &provider)
Evaluate a descriptor given as a string, or as a {"desc":...,"range":...} object, with default range ...
Definition: util.cpp:1362
const std::string UNIX_EPOCH_TIME
String used to describe UNIX epoch time in documentation, factored out to a constant for consistency.
Definition: util.cpp:25
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded values (throws error if not hex).
Definition: util.cpp:76
@ SER_NETWORK
Definition: serialize.h:152
size_t GetSerializeSize(const T &t, int nVersion=0)
Definition: serialize.h:1258
void WriteCompactSize(CSizeComputer &os, uint64_t nSize)
Definition: serialize.h:1254
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 & EnsureArgsman(const NodeContext &node)
Definition: server_util.cpp:41
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:61
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:206
@ OMITTED
Optional argument for which the default value is omitted from help text 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:143
bool skip_type_check
Definition: util.h:140
@ ELISION
Special type to denote elision (...)
@ NUM_TIME
Special numeric to denote unix epoch time.
@ STR_HEX
Special string with only hex chars.
@ STR_AMOUNT
Special string to represent a floating point amount.
A TxId is the identifier of a transaction.
Definition: txid.h:14
uint64_t nDiskSize
Definition: coinstats.h:36
Amount total_unspendables_scripts
Total cumulative amount of outputs sent to unspendable scripts (OP_RETURN for example) up to and incl...
Definition: coinstats.h:67
Amount total_coinbase_amount
Total cumulative amount of coinbase outputs up to and including this block.
Definition: coinstats.h:60
Amount total_unspendables_genesis_block
The unspendable coinbase amount from the genesis block.
Definition: coinstats.h:62
uint64_t nTransactions
Definition: coinstats.h:32
uint64_t nTransactionOutputs
Definition: coinstats.h:33
uint64_t nBogoSize
Definition: coinstats.h:34
bool index_used
Signals if the coinstatsindex was used to retrieve the statistics.
Definition: coinstats.h:43
Amount total_unspendables_bip30
The two unspendable coinbase outputs total amount caused by BIP30.
Definition: coinstats.h:64
Amount total_prevout_spent_amount
Total cumulative amount of prevouts spent up to and including this block.
Definition: coinstats.h:54
BlockHash hashBlock
Definition: coinstats.h:31
Amount total_unspendables_unclaimed_rewards
Total cumulative amount of coins lost due to unclaimed miner rewards up to and including this block.
Definition: coinstats.h:70
uint256 hashSerialized
Definition: coinstats.h:35
Amount total_new_outputs_ex_coinbase_amount
Total cumulative amount of outputs created up to and including this block.
Definition: coinstats.h:57
Amount total_unspendable_amount
Total cumulative amount of unspendable coins up to and including this block.
Definition: coinstats.h:52
NodeContext struct containing references to chain state and connection state.
Definition: context.h:46
#define WAIT_LOCK(cs, name)
Definition: sync.h:317
#define AssertLockNotHeld(cs)
Definition: sync.h:163
#define LOCK(cs)
Definition: sync.h:306
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:357
static int count
Definition: tests.c:31
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:56
#define LOG_TIME_SECONDS(end_msg)
Definition: timer.h:103
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1202
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:68
static const uint32_t MEMPOOL_HEIGHT
Fake height value used in Coins to signify they are only in the memory pool(since 0....
Definition: txmempool.h:50
uint256 uint256S(const char *str)
uint256 from const char *.
Definition: uint256.h:143
const UniValue NullUniValue
Definition: univalue.cpp:16
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Amount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams)
double GuessVerificationProgress(const ChainTxData &data, const CBlockIndex *pindex)
Guess how far we are in the verification process at the given block index require cs_main if pindex h...
const std::vector< std::string > CHECKLEVEL_DOC
Documentation for argument 'checklevel'.
Definition: validation.cpp:100
void PruneBlockFilesManual(Chainstate &active_chainstate, int nManualPruneHeight)
Prune block files up to a given height.
AssertLockHeld(pool.cs)
static constexpr int DEFAULT_CHECKLEVEL
Definition: validation.h:98
static const unsigned int MIN_BLOCKS_TO_KEEP
Block files containing a block-height within MIN_BLOCKS_TO_KEEP of ActiveChain().Tip() will not be pr...
Definition: validation.h:96
static const signed int DEFAULT_CHECKBLOCKS
Definition: validation.h:97
void SyncWithValidationInterfaceQueue()
This is a synonym for the following, which asserts certain locks are not held: std::promise<void> pro...
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:11
bilingual_str GetWarnings(bool verbose)
Format a string that describes several potential problems detected by the core.
Definition: warnings.cpp:41