Bitcoin Core 28.0.0
P2P Digital Currency
Loading...
Searching...
No Matches
blockchain.cpp
Go to the documentation of this file.
1// Copyright (c) 2010 Satoshi Nakamoto
2// Copyright (c) 2009-2022 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 <chainparamsbase.h>
12#include <clientversion.h>
13#include <coins.h>
14#include <common/args.h>
15#include <consensus/amount.h>
16#include <consensus/params.h>
18#include <core_io.h>
19#include <deploymentinfo.h>
20#include <deploymentstatus.h>
21#include <flatfile.h>
22#include <hash.h>
25#include <kernel/coinstats.h>
26#include <logging/timer.h>
27#include <net.h>
28#include <net_processing.h>
29#include <node/blockstorage.h>
30#include <node/context.h>
31#include <node/transaction.h>
32#include <node/utxo_snapshot.h>
33#include <node/warnings.h>
35#include <rpc/server.h>
36#include <rpc/server_util.h>
37#include <rpc/util.h>
38#include <script/descriptor.h>
39#include <serialize.h>
40#include <streams.h>
41#include <sync.h>
42#include <txdb.h>
43#include <txmempool.h>
44#include <undo.h>
45#include <univalue.h>
46#include <util/check.h>
47#include <util/fs.h>
48#include <util/strencodings.h>
49#include <util/translation.h>
50#include <validation.h>
51#include <validationinterface.h>
52#include <versionbits.h>
53
54#include <stdint.h>
55
56#include <condition_variable>
57#include <memory>
58#include <mutex>
59
62
67
69{
71 int height;
72};
73
75static std::condition_variable cond_blockchange;
77
78/* Calculate the difficulty for a given block index.
79 */
80double GetDifficulty(const CBlockIndex& blockindex)
81{
82 int nShift = (blockindex.nBits >> 24) & 0xff;
83 double dDiff =
84 (double)0x0000ffff / (double)(blockindex.nBits & 0x00ffffff);
85
86 while (nShift < 29)
87 {
88 dDiff *= 256.0;
89 nShift++;
90 }
91 while (nShift > 29)
92 {
93 dDiff /= 256.0;
94 nShift--;
95 }
96
97 return dDiff;
98}
99
100static int ComputeNextBlockAndDepth(const CBlockIndex& tip, const CBlockIndex& blockindex, const CBlockIndex*& next)
101{
102 next = tip.GetAncestor(blockindex.nHeight + 1);
103 if (next && next->pprev == &blockindex) {
104 return tip.nHeight - blockindex.nHeight + 1;
105 }
106 next = nullptr;
107 return &blockindex == &tip ? 1 : -1;
108}
109
110static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateManager& chainman)
111{
113 CChain& active_chain = chainman.ActiveChain();
114
115 if (param.isNum()) {
116 const int height{param.getInt<int>()};
117 if (height < 0) {
118 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d is negative", height));
119 }
120 const int current_tip{active_chain.Height()};
121 if (height > current_tip) {
122 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d after current tip %d", height, current_tip));
123 }
124
125 return active_chain[height];
126 } else {
127 const uint256 hash{ParseHashV(param, "hash_or_height")};
128 const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
129
130 if (!pindex) {
131 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
132 }
133
134 return pindex;
135 }
136}
137
138UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex)
139{
140 // Serialize passed information without accessing chain state of the active chain!
141 AssertLockNotHeld(cs_main); // For performance reasons
142
143 UniValue result(UniValue::VOBJ);
144 result.pushKV("hash", blockindex.GetBlockHash().GetHex());
145 const CBlockIndex* pnext;
146 int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
147 result.pushKV("confirmations", confirmations);
148 result.pushKV("height", blockindex.nHeight);
149 result.pushKV("version", blockindex.nVersion);
150 result.pushKV("versionHex", strprintf("%08x", blockindex.nVersion));
151 result.pushKV("merkleroot", blockindex.hashMerkleRoot.GetHex());
152 result.pushKV("time", blockindex.nTime);
153 result.pushKV("mediantime", blockindex.GetMedianTimePast());
154 result.pushKV("nonce", blockindex.nNonce);
155 result.pushKV("bits", strprintf("%08x", blockindex.nBits));
156 result.pushKV("difficulty", GetDifficulty(blockindex));
157 result.pushKV("chainwork", blockindex.nChainWork.GetHex());
158 result.pushKV("nTx", blockindex.nTx);
159
160 if (blockindex.pprev)
161 result.pushKV("previousblockhash", blockindex.pprev->GetBlockHash().GetHex());
162 if (pnext)
163 result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
164 return result;
165}
166
167UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity)
168{
169 UniValue result = blockheaderToJSON(tip, blockindex);
170
171 result.pushKV("strippedsize", (int)::GetSerializeSize(TX_NO_WITNESS(block)));
172 result.pushKV("size", (int)::GetSerializeSize(TX_WITH_WITNESS(block)));
173 result.pushKV("weight", (int)::GetBlockWeight(block));
175
176 switch (verbosity) {
178 for (const CTransactionRef& tx : block.vtx) {
179 txs.push_back(tx->GetHash().GetHex());
180 }
181 break;
182
185 CBlockUndo blockUndo;
186 const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))};
187 const bool have_undo{is_not_pruned && blockman.UndoReadFromDisk(blockUndo, blockindex)};
188
189 for (size_t i = 0; i < block.vtx.size(); ++i) {
190 const CTransactionRef& tx = block.vtx.at(i);
191 // coinbase transaction (i.e. i == 0) doesn't have undo data
192 const CTxUndo* txundo = (have_undo && i > 0) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
194 TxToUniv(*tx, /*block_hash=*/uint256(), /*entry=*/objTx, /*include_hex=*/true, txundo, verbosity);
195 txs.push_back(std::move(objTx));
196 }
197 break;
198 }
199
200 result.pushKV("tx", std::move(txs));
201
202 return result;
203}
204
206{
207 return RPCHelpMan{"getblockcount",
208 "\nReturns the height of the most-work fully-validated chain.\n"
209 "The genesis block has height 0.\n",
210 {},
211 RPCResult{
212 RPCResult::Type::NUM, "", "The current block count"},
214 HelpExampleCli("getblockcount", "")
215 + HelpExampleRpc("getblockcount", "")
216 },
217 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
218{
219 ChainstateManager& chainman = EnsureAnyChainman(request.context);
220 LOCK(cs_main);
221 return chainman.ActiveChain().Height();
222},
223 };
224}
225
227{
228 return RPCHelpMan{"getbestblockhash",
229 "\nReturns the hash of the best (tip) block in the most-work fully-validated chain.\n",
230 {},
231 RPCResult{
232 RPCResult::Type::STR_HEX, "", "the block hash, hex-encoded"},
234 HelpExampleCli("getbestblockhash", "")
235 + HelpExampleRpc("getbestblockhash", "")
236 },
237 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
238{
239 ChainstateManager& chainman = EnsureAnyChainman(request.context);
240 LOCK(cs_main);
241 return chainman.ActiveChain().Tip()->GetBlockHash().GetHex();
242},
243 };
244}
245
247{
248 if(pindex) {
250 latestblock.hash = pindex->GetBlockHash();
251 latestblock.height = pindex->nHeight;
252 }
253 cond_blockchange.notify_all();
254}
255
257{
258 return RPCHelpMan{"waitfornewblock",
259 "\nWaits for a specific new block and returns useful info about it.\n"
260 "\nReturns the current block on timeout or exit.\n",
261 {
262 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
263 },
264 RPCResult{
265 RPCResult::Type::OBJ, "", "",
266 {
267 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
268 {RPCResult::Type::NUM, "height", "Block height"},
269 }},
271 HelpExampleCli("waitfornewblock", "1000")
272 + HelpExampleRpc("waitfornewblock", "1000")
273 },
274 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
275{
276 int timeout = 0;
277 if (!request.params[0].isNull())
278 timeout = request.params[0].getInt<int>();
279
280 CUpdatedBlock block;
281 {
283 block = latestblock;
284 if(timeout)
285 cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
286 else
287 cond_blockchange.wait(lock, [&block]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
288 block = latestblock;
289 }
291 ret.pushKV("hash", block.hash.GetHex());
292 ret.pushKV("height", block.height);
293 return ret;
294},
295 };
296}
297
299{
300 return RPCHelpMan{"waitforblock",
301 "\nWaits for a specific new block and returns useful info about it.\n"
302 "\nReturns the current block on timeout or exit.\n",
303 {
304 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Block hash to wait for."},
305 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
306 },
307 RPCResult{
308 RPCResult::Type::OBJ, "", "",
309 {
310 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
311 {RPCResult::Type::NUM, "height", "Block height"},
312 }},
314 HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\" 1000")
315 + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
316 },
317 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
318{
319 int timeout = 0;
320
321 uint256 hash(ParseHashV(request.params[0], "blockhash"));
322
323 if (!request.params[1].isNull())
324 timeout = request.params[1].getInt<int>();
325
326 CUpdatedBlock block;
327 {
329 if(timeout)
330 cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.hash == hash || !IsRPCRunning();});
331 else
332 cond_blockchange.wait(lock, [&hash]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.hash == hash || !IsRPCRunning(); });
333 block = latestblock;
334 }
335
337 ret.pushKV("hash", block.hash.GetHex());
338 ret.pushKV("height", block.height);
339 return ret;
340},
341 };
342}
343
345{
346 return RPCHelpMan{"waitforblockheight",
347 "\nWaits for (at least) block height and returns the height and hash\n"
348 "of the current tip.\n"
349 "\nReturns the current block on timeout or exit.\n",
350 {
351 {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "Block height to wait for."},
352 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
353 },
354 RPCResult{
355 RPCResult::Type::OBJ, "", "",
356 {
357 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
358 {RPCResult::Type::NUM, "height", "Block height"},
359 }},
361 HelpExampleCli("waitforblockheight", "100 1000")
362 + HelpExampleRpc("waitforblockheight", "100, 1000")
363 },
364 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
365{
366 int timeout = 0;
367
368 int height = request.params[0].getInt<int>();
369
370 if (!request.params[1].isNull())
371 timeout = request.params[1].getInt<int>();
372
373 CUpdatedBlock block;
374 {
376 if(timeout)
377 cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height >= height || !IsRPCRunning();});
378 else
379 cond_blockchange.wait(lock, [&height]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height >= height || !IsRPCRunning(); });
380 block = latestblock;
381 }
383 ret.pushKV("hash", block.hash.GetHex());
384 ret.pushKV("height", block.height);
385 return ret;
386},
387 };
388}
389
391{
392 return RPCHelpMan{"syncwithvalidationinterfacequeue",
393 "\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n",
394 {},
397 HelpExampleCli("syncwithvalidationinterfacequeue","")
398 + HelpExampleRpc("syncwithvalidationinterfacequeue","")
399 },
400 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
401{
402 NodeContext& node = EnsureAnyNodeContext(request.context);
403 CHECK_NONFATAL(node.validation_signals)->SyncWithValidationInterfaceQueue();
404 return UniValue::VNULL;
405},
406 };
407}
408
410{
411 return RPCHelpMan{"getdifficulty",
412 "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n",
413 {},
414 RPCResult{
415 RPCResult::Type::NUM, "", "the proof-of-work difficulty as a multiple of the minimum difficulty."},
417 HelpExampleCli("getdifficulty", "")
418 + HelpExampleRpc("getdifficulty", "")
419 },
420 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
421{
422 ChainstateManager& chainman = EnsureAnyChainman(request.context);
423 LOCK(cs_main);
424 return GetDifficulty(*CHECK_NONFATAL(chainman.ActiveChain().Tip()));
425},
426 };
427}
428
430{
431 return RPCHelpMan{
432 "getblockfrompeer",
433 "Attempt to fetch block from a given peer.\n\n"
434 "We must have the header for this block, e.g. using submitheader.\n"
435 "The block will not have any undo data which can limit the usage of the block data in a context where the undo data is needed.\n"
436 "Subsequent calls for the same block may cause the response from the previous peer to be ignored.\n"
437 "Peers generally ignore requests for a stale block that they never fully verified, or one that is more than a month old.\n"
438 "When a peer does not respond with a block, we will disconnect.\n"
439 "Note: The block could be re-pruned as soon as it is received.\n\n"
440 "Returns an empty JSON object if the request was successfully scheduled.",
441 {
442 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash to try to fetch"},
443 {"peer_id", RPCArg::Type::NUM, RPCArg::Optional::NO, "The peer to fetch it from (see getpeerinfo for peer IDs)"},
444 },
445 RPCResult{RPCResult::Type::OBJ, "", /*optional=*/false, "", {}},
447 HelpExampleCli("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0")
448 + HelpExampleRpc("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0")
449 },
450 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
451{
452 const NodeContext& node = EnsureAnyNodeContext(request.context);
454 PeerManager& peerman = EnsurePeerman(node);
455
456 const uint256& block_hash{ParseHashV(request.params[0], "blockhash")};
457 const NodeId peer_id{request.params[1].getInt<int64_t>()};
458
459 const CBlockIndex* const index = WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(block_hash););
460
461 if (!index) {
462 throw JSONRPCError(RPC_MISC_ERROR, "Block header missing");
463 }
464
465 // Fetching blocks before the node has syncing past their height can prevent block files from
466 // being pruned, so we avoid it if the node is in prune mode.
467 if (chainman.m_blockman.IsPruneMode() && index->nHeight > WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip()->nHeight)) {
468 throw JSONRPCError(RPC_MISC_ERROR, "In prune mode, only blocks that the node has already synced previously can be fetched from a peer");
469 }
470
471 const bool block_has_data = WITH_LOCK(::cs_main, return index->nStatus & BLOCK_HAVE_DATA);
472 if (block_has_data) {
473 throw JSONRPCError(RPC_MISC_ERROR, "Block already downloaded");
474 }
475
476 if (const auto err{peerman.FetchBlock(peer_id, *index)}) {
477 throw JSONRPCError(RPC_MISC_ERROR, err.value());
478 }
479 return UniValue::VOBJ;
480},
481 };
482}
483
485{
486 return RPCHelpMan{"getblockhash",
487 "\nReturns hash of block in best-block-chain at height provided.\n",
488 {
489 {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The height index"},
490 },
491 RPCResult{
492 RPCResult::Type::STR_HEX, "", "The block hash"},
494 HelpExampleCli("getblockhash", "1000")
495 + HelpExampleRpc("getblockhash", "1000")
496 },
497 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
498{
499 ChainstateManager& chainman = EnsureAnyChainman(request.context);
500 LOCK(cs_main);
501 const CChain& active_chain = chainman.ActiveChain();
502
503 int nHeight = request.params[0].getInt<int>();
504 if (nHeight < 0 || nHeight > active_chain.Height())
505 throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
506
507 const CBlockIndex* pblockindex = active_chain[nHeight];
508 return pblockindex->GetBlockHash().GetHex();
509},
510 };
511}
512
514{
515 return RPCHelpMan{"getblockheader",
516 "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"
517 "If verbose is true, returns an Object with information about blockheader <hash>.\n",
518 {
519 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
520 {"verbose", RPCArg::Type::BOOL, RPCArg::Default{true}, "true for a json object, false for the hex-encoded data"},
521 },
522 {
523 RPCResult{"for verbose = true",
524 RPCResult::Type::OBJ, "", "",
525 {
526 {RPCResult::Type::STR_HEX, "hash", "the block hash (same as provided)"},
527 {RPCResult::Type::NUM, "confirmations", "The number of confirmations, or -1 if the block is not on the main chain"},
528 {RPCResult::Type::NUM, "height", "The block height or index"},
529 {RPCResult::Type::NUM, "version", "The block version"},
530 {RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},
531 {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
532 {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
533 {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
534 {RPCResult::Type::NUM, "nonce", "The nonce"},
535 {RPCResult::Type::STR_HEX, "bits", "The bits"},
536 {RPCResult::Type::NUM, "difficulty", "The difficulty"},
537 {RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the current chain"},
538 {RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
539 {RPCResult::Type::STR_HEX, "previousblockhash", /*optional=*/true, "The hash of the previous block (if available)"},
540 {RPCResult::Type::STR_HEX, "nextblockhash", /*optional=*/true, "The hash of the next block (if available)"},
541 }},
542 RPCResult{"for verbose=false",
543 RPCResult::Type::STR_HEX, "", "A string that is serialized, hex-encoded data for block 'hash'"},
544 },
546 HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
547 + HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
548 },
549 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
550{
551 uint256 hash(ParseHashV(request.params[0], "hash"));
552
553 bool fVerbose = true;
554 if (!request.params[1].isNull())
555 fVerbose = request.params[1].get_bool();
556
557 const CBlockIndex* pblockindex;
558 const CBlockIndex* tip;
559 {
560 ChainstateManager& chainman = EnsureAnyChainman(request.context);
561 LOCK(cs_main);
562 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
563 tip = chainman.ActiveChain().Tip();
564 }
565
566 if (!pblockindex) {
567 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
568 }
569
570 if (!fVerbose)
571 {
572 DataStream ssBlock{};
573 ssBlock << pblockindex->GetBlockHeader();
574 std::string strHex = HexStr(ssBlock);
575 return strHex;
576 }
577
578 return blockheaderToJSON(*tip, *pblockindex);
579},
580 };
581}
582
583static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex& blockindex)
584{
585 CBlock block;
586 {
587 LOCK(cs_main);
588 if (blockman.IsBlockPruned(blockindex)) {
589 throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
590 }
591 }
592
593 if (!blockman.ReadBlockFromDisk(block, blockindex)) {
594 // Block not found on disk. This could be because we have the block
595 // header in our index but not yet have the block or did not accept the
596 // block. Or if the block was pruned right after we released the lock above.
597 throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
598 }
599
600 return block;
601}
602
603static std::vector<uint8_t> GetRawBlockChecked(BlockManager& blockman, const CBlockIndex& blockindex)
604{
605 std::vector<uint8_t> data{};
606 FlatFilePos pos{};
607 {
608 LOCK(cs_main);
609 if (blockman.IsBlockPruned(blockindex)) {
610 throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
611 }
612 pos = blockindex.GetBlockPos();
613 }
614
615 if (!blockman.ReadRawBlockFromDisk(data, pos)) {
616 // Block not found on disk. This could be because we have the block
617 // header in our index but not yet have the block or did not accept the
618 // block. Or if the block was pruned right after we released the lock above.
619 throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
620 }
621
622 return data;
623}
624
625static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex& blockindex)
626{
627 CBlockUndo blockUndo;
628
629 // The Genesis block does not have undo data
630 if (blockindex.nHeight == 0) return blockUndo;
631
632 {
633 LOCK(cs_main);
634 if (blockman.IsBlockPruned(blockindex)) {
635 throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)");
636 }
637 }
638
639 if (!blockman.UndoReadFromDisk(blockUndo, blockindex)) {
640 throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
641 }
642
643 return blockUndo;
644}
645
647 RPCResult::Type::ARR, "vin", "",
648 {
649 {RPCResult::Type::OBJ, "", "",
650 {
651 {RPCResult::Type::ELISION, "", "The same output as verbosity = 2"},
652 {RPCResult::Type::OBJ, "prevout", "(Only if undo information is available)",
653 {
654 {RPCResult::Type::BOOL, "generated", "Coinbase or not"},
655 {RPCResult::Type::NUM, "height", "The height of the prevout"},
656 {RPCResult::Type::STR_AMOUNT, "value", "The value in " + CURRENCY_UNIT},
657 {RPCResult::Type::OBJ, "scriptPubKey", "",
658 {
659 {RPCResult::Type::STR, "asm", "Disassembly of the output script"},
660 {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
661 {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"},
662 {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
663 {RPCResult::Type::STR, "type", "The type (one of: " + GetAllOutputTypes() + ")"},
664 }},
665 }},
666 }},
667 }
668};
669
671{
672 return RPCHelpMan{"getblock",
673 "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
674 "If verbosity is 1, returns an Object with information about block <hash>.\n"
675 "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction.\n"
676 "If verbosity is 3, returns an Object with information about block <hash> and information about each transaction, including prevout information for inputs (only for unpruned blocks in the current best chain).\n",
677 {
678 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
679 {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1}, "0 for hex-encoded data, 1 for a JSON object, 2 for JSON object with transaction data, and 3 for JSON object with transaction data including prevout information for inputs",
680 RPCArgOptions{.skip_type_check = true}},
681 },
682 {
683 RPCResult{"for verbosity = 0",
684 RPCResult::Type::STR_HEX, "", "A string that is serialized, hex-encoded data for block 'hash'"},
685 RPCResult{"for verbosity = 1",
686 RPCResult::Type::OBJ, "", "",
687 {
688 {RPCResult::Type::STR_HEX, "hash", "the block hash (same as provided)"},
689 {RPCResult::Type::NUM, "confirmations", "The number of confirmations, or -1 if the block is not on the main chain"},
690 {RPCResult::Type::NUM, "size", "The block size"},
691 {RPCResult::Type::NUM, "strippedsize", "The block size excluding witness data"},
692 {RPCResult::Type::NUM, "weight", "The block weight as defined in BIP 141"},
693 {RPCResult::Type::NUM, "height", "The block height or index"},
694 {RPCResult::Type::NUM, "version", "The block version"},
695 {RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},
696 {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
697 {RPCResult::Type::ARR, "tx", "The transaction ids",
698 {{RPCResult::Type::STR_HEX, "", "The transaction id"}}},
699 {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
700 {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
701 {RPCResult::Type::NUM, "nonce", "The nonce"},
702 {RPCResult::Type::STR_HEX, "bits", "The bits"},
703 {RPCResult::Type::NUM, "difficulty", "The difficulty"},
704 {RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the chain up to this block (in hex)"},
705 {RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
706 {RPCResult::Type::STR_HEX, "previousblockhash", /*optional=*/true, "The hash of the previous block (if available)"},
707 {RPCResult::Type::STR_HEX, "nextblockhash", /*optional=*/true, "The hash of the next block (if available)"},
708 }},
709 RPCResult{"for verbosity = 2",
710 RPCResult::Type::OBJ, "", "",
711 {
712 {RPCResult::Type::ELISION, "", "Same output as verbosity = 1"},
713 {RPCResult::Type::ARR, "tx", "",
714 {
715 {RPCResult::Type::OBJ, "", "",
716 {
717 {RPCResult::Type::ELISION, "", "The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result"},
718 {RPCResult::Type::NUM, "fee", "The transaction fee in " + CURRENCY_UNIT + ", omitted if block undo data is not available"},
719 }},
720 }},
721 }},
722 RPCResult{"for verbosity = 3",
723 RPCResult::Type::OBJ, "", "",
724 {
725 {RPCResult::Type::ELISION, "", "Same output as verbosity = 2"},
726 {RPCResult::Type::ARR, "tx", "",
727 {
728 {RPCResult::Type::OBJ, "", "",
729 {
731 }},
732 }},
733 }},
734 },
736 HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
737 + HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
738 },
739 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
740{
741 uint256 hash(ParseHashV(request.params[0], "blockhash"));
742
743 int verbosity = 1;
744 if (!request.params[1].isNull()) {
745 if (request.params[1].isBool()) {
746 verbosity = request.params[1].get_bool() ? 1 : 0;
747 } else {
748 verbosity = request.params[1].getInt<int>();
749 }
750 }
751
752 const CBlockIndex* pblockindex;
753 const CBlockIndex* tip;
754 ChainstateManager& chainman = EnsureAnyChainman(request.context);
755 {
756 LOCK(cs_main);
757 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
758 tip = chainman.ActiveChain().Tip();
759
760 if (!pblockindex) {
761 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
762 }
763 }
764
765 const std::vector<uint8_t> block_data{GetRawBlockChecked(chainman.m_blockman, *pblockindex)};
766
767 if (verbosity <= 0) {
768 return HexStr(block_data);
769 }
770
771 DataStream block_stream{block_data};
772 CBlock block{};
773 block_stream >> TX_WITH_WITNESS(block);
774
775 TxVerbosity tx_verbosity;
776 if (verbosity == 1) {
777 tx_verbosity = TxVerbosity::SHOW_TXID;
778 } else if (verbosity == 2) {
779 tx_verbosity = TxVerbosity::SHOW_DETAILS;
780 } else {
782 }
783
784 return blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity);
785},
786 };
787}
788
790std::optional<int> GetPruneHeight(const BlockManager& blockman, const CChain& chain) {
792
793 // Search for the last block missing block data or undo data. Don't let the
794 // search consider the genesis block, because the genesis block does not
795 // have undo data, but should not be considered pruned.
796 const CBlockIndex* first_block{chain[1]};
797 const CBlockIndex* chain_tip{chain.Tip()};
798
799 // If there are no blocks after the genesis block, or no blocks at all, nothing is pruned.
800 if (!first_block || !chain_tip) return std::nullopt;
801
802 // If the chain tip is pruned, everything is pruned.
803 if (!((chain_tip->nStatus & BLOCK_HAVE_MASK) == BLOCK_HAVE_MASK)) return chain_tip->nHeight;
804
805 const auto& first_unpruned{*CHECK_NONFATAL(blockman.GetFirstBlock(*chain_tip, /*status_mask=*/BLOCK_HAVE_MASK, first_block))};
806 if (&first_unpruned == first_block) {
807 // All blocks between first_block and chain_tip have data, so nothing is pruned.
808 return std::nullopt;
809 }
810
811 // Block before the first unpruned block is the last pruned block.
812 return CHECK_NONFATAL(first_unpruned.pprev)->nHeight;
813}
814
816{
817 return RPCHelpMan{"pruneblockchain", "",
818 {
819 {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block height to prune up to. May be set to a discrete height, or to a " + UNIX_EPOCH_TIME + "\n"
820 " to prune blocks whose block time is at least 2 hours older than the provided timestamp."},
821 },
822 RPCResult{
823 RPCResult::Type::NUM, "", "Height of the last block pruned"},
825 HelpExampleCli("pruneblockchain", "1000")
826 + HelpExampleRpc("pruneblockchain", "1000")
827 },
828 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
829{
830 ChainstateManager& chainman = EnsureAnyChainman(request.context);
831 if (!chainman.m_blockman.IsPruneMode()) {
832 throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
833 }
834
835 LOCK(cs_main);
836 Chainstate& active_chainstate = chainman.ActiveChainstate();
837 CChain& active_chain = active_chainstate.m_chain;
838
839 int heightParam = request.params[0].getInt<int>();
840 if (heightParam < 0) {
841 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative block height.");
842 }
843
844 // Height value more than a billion is too high to be a block height, and
845 // too low to be a block time (corresponds to timestamp from Sep 2001).
846 if (heightParam > 1000000000) {
847 // Add a 2 hour buffer to include blocks which might have had old timestamps
848 const CBlockIndex* pindex = active_chain.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0);
849 if (!pindex) {
850 throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp.");
851 }
852 heightParam = pindex->nHeight;
853 }
854
855 unsigned int height = (unsigned int) heightParam;
856 unsigned int chainHeight = (unsigned int) active_chain.Height();
857 if (chainHeight < chainman.GetParams().PruneAfterHeight()) {
858 throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning.");
859 } else if (height > chainHeight) {
860 throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height.");
861 } else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
862 LogPrint(BCLog::RPC, "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks.\n");
863 height = chainHeight - MIN_BLOCKS_TO_KEEP;
864 }
865
866 PruneBlockFilesManual(active_chainstate, height);
867 return GetPruneHeight(chainman.m_blockman, active_chain).value_or(-1);
868},
869 };
870}
871
872CoinStatsHashType ParseHashType(const std::string& hash_type_input)
873{
874 if (hash_type_input == "hash_serialized_3") {
876 } else if (hash_type_input == "muhash") {
878 } else if (hash_type_input == "none") {
880 } else {
881 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("'%s' is not a valid hash_type", hash_type_input));
882 }
883}
884
890static std::optional<kernel::CCoinsStats> GetUTXOStats(CCoinsView* view, node::BlockManager& blockman,
892 const std::function<void()>& interruption_point = {},
893 const CBlockIndex* pindex = nullptr,
894 bool index_requested = true)
895{
896 // Use CoinStatsIndex if it is requested and available and a hash_type of Muhash or None was requested
897 if ((hash_type == kernel::CoinStatsHashType::MUHASH || hash_type == kernel::CoinStatsHashType::NONE) && g_coin_stats_index && index_requested) {
898 if (pindex) {
899 return g_coin_stats_index->LookUpStats(*pindex);
900 } else {
901 CBlockIndex& block_index = *CHECK_NONFATAL(WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(view->GetBestBlock())));
902 return g_coin_stats_index->LookUpStats(block_index);
903 }
904 }
905
906 // If the coinstats index isn't requested or is otherwise not usable, the
907 // pindex should either be null or equal to the view's best block. This is
908 // because without the coinstats index we can only get coinstats about the
909 // best block.
910 CHECK_NONFATAL(!pindex || pindex->GetBlockHash() == view->GetBestBlock());
911
912 return kernel::ComputeUTXOStats(hash_type, view, blockman, interruption_point);
913}
914
916{
917 return RPCHelpMan{"gettxoutsetinfo",
918 "\nReturns statistics about the unspent transaction output set.\n"
919 "Note this call may take some time if you are not using coinstatsindex.\n",
920 {
921 {"hash_type", RPCArg::Type::STR, RPCArg::Default{"hash_serialized_3"}, "Which UTXO set hash should be calculated. Options: 'hash_serialized_3' (the legacy algorithm), 'muhash', 'none'."},
922 {"hash_or_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"the current best block"}, "The block hash or height of the target height (only available with coinstatsindex).",
924 .skip_type_check = true,
925 .type_str = {"", "string or numeric"},
926 }},
927 {"use_index", RPCArg::Type::BOOL, RPCArg::Default{true}, "Use coinstatsindex, if available."},
928 },
929 RPCResult{
930 RPCResult::Type::OBJ, "", "",
931 {
932 {RPCResult::Type::NUM, "height", "The block height (index) of the returned statistics"},
933 {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at which these statistics are calculated"},
934 {RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs"},
935 {RPCResult::Type::NUM, "bogosize", "Database-independent, meaningless metric indicating the UTXO set size"},
936 {RPCResult::Type::STR_HEX, "hash_serialized_3", /*optional=*/true, "The serialized hash (only present if 'hash_serialized_3' hash_type is chosen)"},
937 {RPCResult::Type::STR_HEX, "muhash", /*optional=*/true, "The serialized hash (only present if 'muhash' hash_type is chosen)"},
938 {RPCResult::Type::NUM, "transactions", /*optional=*/true, "The number of transactions with unspent outputs (not available when coinstatsindex is used)"},
939 {RPCResult::Type::NUM, "disk_size", /*optional=*/true, "The estimated size of the chainstate on disk (not available when coinstatsindex is used)"},
940 {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of coins in the UTXO set"},
941 {RPCResult::Type::STR_AMOUNT, "total_unspendable_amount", /*optional=*/true, "The total amount of coins permanently excluded from the UTXO set (only available if coinstatsindex is used)"},
942 {RPCResult::Type::OBJ, "block_info", /*optional=*/true, "Info on amounts in the block at this block height (only available if coinstatsindex is used)",
943 {
944 {RPCResult::Type::STR_AMOUNT, "prevout_spent", "Total amount of all prevouts spent in this block"},
945 {RPCResult::Type::STR_AMOUNT, "coinbase", "Coinbase subsidy amount of this block"},
946 {RPCResult::Type::STR_AMOUNT, "new_outputs_ex_coinbase", "Total amount of new outputs created by this block"},
947 {RPCResult::Type::STR_AMOUNT, "unspendable", "Total amount of unspendable outputs created in this block"},
948 {RPCResult::Type::OBJ, "unspendables", "Detailed view of the unspendable categories",
949 {
950 {RPCResult::Type::STR_AMOUNT, "genesis_block", "The unspendable amount of the Genesis block subsidy"},
951 {RPCResult::Type::STR_AMOUNT, "bip30", "Transactions overridden by duplicates (no longer possible with BIP30)"},
952 {RPCResult::Type::STR_AMOUNT, "scripts", "Amounts sent to scripts that are unspendable (for example OP_RETURN outputs)"},
953 {RPCResult::Type::STR_AMOUNT, "unclaimed_rewards", "Fee rewards that miners did not claim in their coinbase transaction"},
954 }}
955 }},
956 }},
958 HelpExampleCli("gettxoutsetinfo", "") +
959 HelpExampleCli("gettxoutsetinfo", R"("none")") +
960 HelpExampleCli("gettxoutsetinfo", R"("none" 1000)") +
961 HelpExampleCli("gettxoutsetinfo", R"("none" '"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"')") +
962 HelpExampleCli("-named gettxoutsetinfo", R"(hash_type='muhash' use_index='false')") +
963 HelpExampleRpc("gettxoutsetinfo", "") +
964 HelpExampleRpc("gettxoutsetinfo", R"("none")") +
965 HelpExampleRpc("gettxoutsetinfo", R"("none", 1000)") +
966 HelpExampleRpc("gettxoutsetinfo", R"("none", "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09")")
967 },
968 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
969{
971
972 const CBlockIndex* pindex{nullptr};
973 const CoinStatsHashType hash_type{request.params[0].isNull() ? CoinStatsHashType::HASH_SERIALIZED : ParseHashType(request.params[0].get_str())};
974 bool index_requested = request.params[2].isNull() || request.params[2].get_bool();
975
976 NodeContext& node = EnsureAnyNodeContext(request.context);
978 Chainstate& active_chainstate = chainman.ActiveChainstate();
979 active_chainstate.ForceFlushStateToDisk();
980
981 CCoinsView* coins_view;
982 BlockManager* blockman;
983 {
985 coins_view = &active_chainstate.CoinsDB();
986 blockman = &active_chainstate.m_blockman;
987 pindex = blockman->LookupBlockIndex(coins_view->GetBestBlock());
988 }
989
990 if (!request.params[1].isNull()) {
991 if (!g_coin_stats_index) {
992 throw JSONRPCError(RPC_INVALID_PARAMETER, "Querying specific block heights requires coinstatsindex");
993 }
994
995 if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
996 throw JSONRPCError(RPC_INVALID_PARAMETER, "hash_serialized_3 hash type cannot be queried for a specific block");
997 }
998
999 if (!index_requested) {
1000 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot set use_index to false when querying for a specific block");
1001 }
1002 pindex = ParseHashOrHeight(request.params[1], chainman);
1003 }
1004
1005 if (index_requested && g_coin_stats_index) {
1006 if (!g_coin_stats_index->BlockUntilSyncedToCurrentChain()) {
1007 const IndexSummary summary{g_coin_stats_index->GetSummary()};
1008
1009 // If a specific block was requested and the index has already synced past that height, we can return the
1010 // data already even though the index is not fully synced yet.
1011 if (pindex->nHeight > summary.best_block_height) {
1012 throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to get data because coinstatsindex is still syncing. Current height: %d", summary.best_block_height));
1013 }
1014 }
1015 }
1016
1017 const std::optional<CCoinsStats> maybe_stats = GetUTXOStats(coins_view, *blockman, hash_type, node.rpc_interruption_point, pindex, index_requested);
1018 if (maybe_stats.has_value()) {
1019 const CCoinsStats& stats = maybe_stats.value();
1020 ret.pushKV("height", (int64_t)stats.nHeight);
1021 ret.pushKV("bestblock", stats.hashBlock.GetHex());
1022 ret.pushKV("txouts", (int64_t)stats.nTransactionOutputs);
1023 ret.pushKV("bogosize", (int64_t)stats.nBogoSize);
1024 if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1025 ret.pushKV("hash_serialized_3", stats.hashSerialized.GetHex());
1026 }
1027 if (hash_type == CoinStatsHashType::MUHASH) {
1028 ret.pushKV("muhash", stats.hashSerialized.GetHex());
1029 }
1030 CHECK_NONFATAL(stats.total_amount.has_value());
1031 ret.pushKV("total_amount", ValueFromAmount(stats.total_amount.value()));
1032 if (!stats.index_used) {
1033 ret.pushKV("transactions", static_cast<int64_t>(stats.nTransactions));
1034 ret.pushKV("disk_size", stats.nDiskSize);
1035 } else {
1036 ret.pushKV("total_unspendable_amount", ValueFromAmount(stats.total_unspendable_amount));
1037
1038 CCoinsStats prev_stats{};
1039 if (pindex->nHeight > 0) {
1040 const std::optional<CCoinsStats> maybe_prev_stats = GetUTXOStats(coins_view, *blockman, hash_type, node.rpc_interruption_point, pindex->pprev, index_requested);
1041 if (!maybe_prev_stats) {
1042 throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
1043 }
1044 prev_stats = maybe_prev_stats.value();
1045 }
1046
1047 UniValue block_info(UniValue::VOBJ);
1048 block_info.pushKV("prevout_spent", ValueFromAmount(stats.total_prevout_spent_amount - prev_stats.total_prevout_spent_amount));
1049 block_info.pushKV("coinbase", ValueFromAmount(stats.total_coinbase_amount - prev_stats.total_coinbase_amount));
1050 block_info.pushKV("new_outputs_ex_coinbase", ValueFromAmount(stats.total_new_outputs_ex_coinbase_amount - prev_stats.total_new_outputs_ex_coinbase_amount));
1051 block_info.pushKV("unspendable", ValueFromAmount(stats.total_unspendable_amount - prev_stats.total_unspendable_amount));
1052
1053 UniValue unspendables(UniValue::VOBJ);
1054 unspendables.pushKV("genesis_block", ValueFromAmount(stats.total_unspendables_genesis_block - prev_stats.total_unspendables_genesis_block));
1055 unspendables.pushKV("bip30", ValueFromAmount(stats.total_unspendables_bip30 - prev_stats.total_unspendables_bip30));
1056 unspendables.pushKV("scripts", ValueFromAmount(stats.total_unspendables_scripts - prev_stats.total_unspendables_scripts));
1057 unspendables.pushKV("unclaimed_rewards", ValueFromAmount(stats.total_unspendables_unclaimed_rewards - prev_stats.total_unspendables_unclaimed_rewards));
1058 block_info.pushKV("unspendables", std::move(unspendables));
1059
1060 ret.pushKV("block_info", std::move(block_info));
1061 }
1062 } else {
1063 throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
1064 }
1065 return ret;
1066},
1067 };
1068}
1069
1071{
1072 return RPCHelpMan{"gettxout",
1073 "\nReturns details about an unspent transaction output.\n",
1074 {
1075 {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
1076 {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
1077 {"include_mempool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to include the mempool. Note that an unspent output that is spent in the mempool won't appear."},
1078 },
1079 {
1080 RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "", ""},
1081 RPCResult{"Otherwise", RPCResult::Type::OBJ, "", "", {
1082 {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
1083 {RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
1084 {RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT},
1085 {RPCResult::Type::OBJ, "scriptPubKey", "", {
1086 {RPCResult::Type::STR, "asm", "Disassembly of the output script"},
1087 {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
1088 {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"},
1089 {RPCResult::Type::STR, "type", "The type, eg pubkeyhash"},
1090 {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
1091 }},
1092 {RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
1093 }},
1094 },
1096 "\nGet unspent transactions\n"
1097 + HelpExampleCli("listunspent", "") +
1098 "\nView the details\n"
1099 + HelpExampleCli("gettxout", "\"txid\" 1") +
1100 "\nAs a JSON-RPC call\n"
1101 + HelpExampleRpc("gettxout", "\"txid\", 1")
1102 },
1103 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1104{
1105 NodeContext& node = EnsureAnyNodeContext(request.context);
1107 LOCK(cs_main);
1108
1110
1111 auto hash{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
1112 COutPoint out{hash, request.params[1].getInt<uint32_t>()};
1113 bool fMempool = true;
1114 if (!request.params[2].isNull())
1115 fMempool = request.params[2].get_bool();
1116
1117 Coin coin;
1118 Chainstate& active_chainstate = chainman.ActiveChainstate();
1119 CCoinsViewCache* coins_view = &active_chainstate.CoinsTip();
1120
1121 if (fMempool) {
1122 const CTxMemPool& mempool = EnsureMemPool(node);
1123 LOCK(mempool.cs);
1124 CCoinsViewMemPool view(coins_view, mempool);
1125 if (!view.GetCoin(out, coin) || mempool.isSpent(out)) {
1126 return UniValue::VNULL;
1127 }
1128 } else {
1129 if (!coins_view->GetCoin(out, coin)) {
1130 return UniValue::VNULL;
1131 }
1132 }
1133
1134 const CBlockIndex* pindex = active_chainstate.m_blockman.LookupBlockIndex(coins_view->GetBestBlock());
1135 ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
1136 if (coin.nHeight == MEMPOOL_HEIGHT) {
1137 ret.pushKV("confirmations", 0);
1138 } else {
1139 ret.pushKV("confirmations", (int64_t)(pindex->nHeight - coin.nHeight + 1));
1140 }
1141 ret.pushKV("value", ValueFromAmount(coin.out.nValue));
1143 ScriptToUniv(coin.out.scriptPubKey, /*out=*/o, /*include_hex=*/true, /*include_address=*/true);
1144 ret.pushKV("scriptPubKey", std::move(o));
1145 ret.pushKV("coinbase", (bool)coin.fCoinBase);
1146
1147 return ret;
1148},
1149 };
1150}
1151
1153{
1154 return RPCHelpMan{"verifychain",
1155 "\nVerifies blockchain database.\n",
1156 {
1157 {"checklevel", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL)},
1158 strprintf("How thorough the block verification is:\n%s", MakeUnorderedList(CHECKLEVEL_DOC))},
1159 {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, 0=all", DEFAULT_CHECKBLOCKS)}, "The number of blocks to check."},
1160 },
1161 RPCResult{
1162 RPCResult::Type::BOOL, "", "Verification finished successfully. If false, check debug.log for reason."},
1164 HelpExampleCli("verifychain", "")
1165 + HelpExampleRpc("verifychain", "")
1166 },
1167 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1168{
1169 const int check_level{request.params[0].isNull() ? DEFAULT_CHECKLEVEL : request.params[0].getInt<int>()};
1170 const int check_depth{request.params[1].isNull() ? DEFAULT_CHECKBLOCKS : request.params[1].getInt<int>()};
1171
1172 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1173 LOCK(cs_main);
1174
1175 Chainstate& active_chainstate = chainman.ActiveChainstate();
1176 return CVerifyDB(chainman.GetNotifications()).VerifyDB(
1177 active_chainstate, chainman.GetParams().GetConsensus(), active_chainstate.CoinsTip(), check_level, check_depth) == VerifyDBResult::SUCCESS;
1178},
1179 };
1180}
1181
1182static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const ChainstateManager& chainman, Consensus::BuriedDeployment dep)
1183{
1184 // For buried deployments.
1185
1186 if (!DeploymentEnabled(chainman, dep)) return;
1187
1189 rv.pushKV("type", "buried");
1190 // getdeploymentinfo reports the softfork as active from when the chain height is
1191 // one below the activation height
1192 rv.pushKV("active", DeploymentActiveAfter(blockindex, chainman, dep));
1193 rv.pushKV("height", chainman.GetConsensus().DeploymentHeight(dep));
1194 softforks.pushKV(DeploymentName(dep), std::move(rv));
1195}
1196
1197static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const ChainstateManager& chainman, Consensus::DeploymentPos id)
1198{
1199 // For BIP9 deployments.
1200
1201 if (!DeploymentEnabled(chainman, id)) return;
1202 if (blockindex == nullptr) return;
1203
1204 auto get_state_name = [](const ThresholdState state) -> std::string {
1205 switch (state) {
1206 case ThresholdState::DEFINED: return "defined";
1207 case ThresholdState::STARTED: return "started";
1208 case ThresholdState::LOCKED_IN: return "locked_in";
1209 case ThresholdState::ACTIVE: return "active";
1210 case ThresholdState::FAILED: return "failed";
1211 }
1212 return "invalid";
1213 };
1214
1216
1217 const ThresholdState next_state = chainman.m_versionbitscache.State(blockindex, chainman.GetConsensus(), id);
1218 const ThresholdState current_state = chainman.m_versionbitscache.State(blockindex->pprev, chainman.GetConsensus(), id);
1219
1220 const bool has_signal = (ThresholdState::STARTED == current_state || ThresholdState::LOCKED_IN == current_state);
1221
1222 // BIP9 parameters
1223 if (has_signal) {
1224 bip9.pushKV("bit", chainman.GetConsensus().vDeployments[id].bit);
1225 }
1226 bip9.pushKV("start_time", chainman.GetConsensus().vDeployments[id].nStartTime);
1227 bip9.pushKV("timeout", chainman.GetConsensus().vDeployments[id].nTimeout);
1228 bip9.pushKV("min_activation_height", chainman.GetConsensus().vDeployments[id].min_activation_height);
1229
1230 // BIP9 status
1231 bip9.pushKV("status", get_state_name(current_state));
1232 bip9.pushKV("since", chainman.m_versionbitscache.StateSinceHeight(blockindex->pprev, chainman.GetConsensus(), id));
1233 bip9.pushKV("status_next", get_state_name(next_state));
1234
1235 // BIP9 signalling status, if applicable
1236 if (has_signal) {
1237 UniValue statsUV(UniValue::VOBJ);
1238 std::vector<bool> signals;
1239 BIP9Stats statsStruct = chainman.m_versionbitscache.Statistics(blockindex, chainman.GetConsensus(), id, &signals);
1240 statsUV.pushKV("period", statsStruct.period);
1241 statsUV.pushKV("elapsed", statsStruct.elapsed);
1242 statsUV.pushKV("count", statsStruct.count);
1243 if (ThresholdState::LOCKED_IN != current_state) {
1244 statsUV.pushKV("threshold", statsStruct.threshold);
1245 statsUV.pushKV("possible", statsStruct.possible);
1246 }
1247 bip9.pushKV("statistics", std::move(statsUV));
1248
1249 std::string sig;
1250 sig.reserve(signals.size());
1251 for (const bool s : signals) {
1252 sig.push_back(s ? '#' : '-');
1253 }
1254 bip9.pushKV("signalling", sig);
1255 }
1256
1258 rv.pushKV("type", "bip9");
1259 if (ThresholdState::ACTIVE == next_state) {
1260 rv.pushKV("height", chainman.m_versionbitscache.StateSinceHeight(blockindex, chainman.GetConsensus(), id));
1261 }
1262 rv.pushKV("active", ThresholdState::ACTIVE == next_state);
1263 rv.pushKV("bip9", std::move(bip9));
1264
1265 softforks.pushKV(DeploymentName(id), std::move(rv));
1266}
1267
1268// used by rest.cpp:rest_chaininfo, so cannot be static
1270{
1271 return RPCHelpMan{"getblockchaininfo",
1272 "Returns an object containing various state info regarding blockchain processing.\n",
1273 {},
1274 RPCResult{
1275 RPCResult::Type::OBJ, "", "",
1276 {
1277 {RPCResult::Type::STR, "chain", "current network name (" LIST_CHAIN_NAMES ")"},
1278 {RPCResult::Type::NUM, "blocks", "the height of the most-work fully-validated chain. The genesis block has height 0"},
1279 {RPCResult::Type::NUM, "headers", "the current number of headers we have validated"},
1280 {RPCResult::Type::STR, "bestblockhash", "the hash of the currently best block"},
1281 {RPCResult::Type::NUM, "difficulty", "the current difficulty"},
1282 {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
1283 {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
1284 {RPCResult::Type::NUM, "verificationprogress", "estimate of verification progress [0..1]"},
1285 {RPCResult::Type::BOOL, "initialblockdownload", "(debug information) estimate of whether this node is in Initial Block Download mode"},
1286 {RPCResult::Type::STR_HEX, "chainwork", "total amount of work in active chain, in hexadecimal"},
1287 {RPCResult::Type::NUM, "size_on_disk", "the estimated size of the block and undo files on disk"},
1288 {RPCResult::Type::BOOL, "pruned", "if the blocks are subject to pruning"},
1289 {RPCResult::Type::NUM, "pruneheight", /*optional=*/true, "height of the last block pruned, plus one (only present if pruning is enabled)"},
1290 {RPCResult::Type::BOOL, "automatic_pruning", /*optional=*/true, "whether automatic pruning is enabled (only present if pruning is enabled)"},
1291 {RPCResult::Type::NUM, "prune_target_size", /*optional=*/true, "the target size used by pruning (only present if automatic pruning is enabled)"},
1292 (IsDeprecatedRPCEnabled("warnings") ?
1293 RPCResult{RPCResult::Type::STR, "warnings", "any network and blockchain warnings (DEPRECATED)"} :
1294 RPCResult{RPCResult::Type::ARR, "warnings", "any network and blockchain warnings (run with `-deprecatedrpc=warnings` to return the latest warning as a single string)",
1295 {
1296 {RPCResult::Type::STR, "", "warning"},
1297 }
1298 }
1299 ),
1300 }},
1302 HelpExampleCli("getblockchaininfo", "")
1303 + HelpExampleRpc("getblockchaininfo", "")
1304 },
1305 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1306{
1307 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1308 LOCK(cs_main);
1309 Chainstate& active_chainstate = chainman.ActiveChainstate();
1310
1311 const CBlockIndex& tip{*CHECK_NONFATAL(active_chainstate.m_chain.Tip())};
1312 const int height{tip.nHeight};
1314 obj.pushKV("chain", chainman.GetParams().GetChainTypeString());
1315 obj.pushKV("blocks", height);
1316 obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
1317 obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex());
1318 obj.pushKV("difficulty", GetDifficulty(tip));
1319 obj.pushKV("time", tip.GetBlockTime());
1320 obj.pushKV("mediantime", tip.GetMedianTimePast());
1321 obj.pushKV("verificationprogress", GuessVerificationProgress(chainman.GetParams().TxData(), &tip));
1322 obj.pushKV("initialblockdownload", chainman.IsInitialBlockDownload());
1323 obj.pushKV("chainwork", tip.nChainWork.GetHex());
1324 obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage());
1325 obj.pushKV("pruned", chainman.m_blockman.IsPruneMode());
1326 if (chainman.m_blockman.IsPruneMode()) {
1327 const auto prune_height{GetPruneHeight(chainman.m_blockman, active_chainstate.m_chain)};
1328 obj.pushKV("pruneheight", prune_height ? prune_height.value() + 1 : 0);
1329
1330 const bool automatic_pruning{chainman.m_blockman.GetPruneTarget() != BlockManager::PRUNE_TARGET_MANUAL};
1331 obj.pushKV("automatic_pruning", automatic_pruning);
1332 if (automatic_pruning) {
1333 obj.pushKV("prune_target_size", chainman.m_blockman.GetPruneTarget());
1334 }
1335 }
1336
1337 NodeContext& node = EnsureAnyNodeContext(request.context);
1338 obj.pushKV("warnings", node::GetWarningsForRpc(*CHECK_NONFATAL(node.warnings), IsDeprecatedRPCEnabled("warnings")));
1339 return obj;
1340},
1341 };
1342}
1343
1344namespace {
1345const std::vector<RPCResult> RPCHelpForDeployment{
1346 {RPCResult::Type::STR, "type", "one of \"buried\", \"bip9\""},
1347 {RPCResult::Type::NUM, "height", /*optional=*/true, "height of the first block which the rules are or will be enforced (only for \"buried\" type, or \"bip9\" type with \"active\" status)"},
1348 {RPCResult::Type::BOOL, "active", "true if the rules are enforced for the mempool and the next block"},
1349 {RPCResult::Type::OBJ, "bip9", /*optional=*/true, "status of bip9 softforks (only for \"bip9\" type)",
1350 {
1351 {RPCResult::Type::NUM, "bit", /*optional=*/true, "the bit (0-28) in the block version field used to signal this softfork (only for \"started\" and \"locked_in\" status)"},
1352 {RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"},
1353 {RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"},
1354 {RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"},
1355 {RPCResult::Type::STR, "status", "status of deployment at specified block (one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\")"},
1356 {RPCResult::Type::NUM, "since", "height of the first block to which the status applies"},
1357 {RPCResult::Type::STR, "status_next", "status of deployment at the next block"},
1358 {RPCResult::Type::OBJ, "statistics", /*optional=*/true, "numeric statistics about signalling for a softfork (only for \"started\" and \"locked_in\" status)",
1359 {
1360 {RPCResult::Type::NUM, "period", "the length in blocks of the signalling period"},
1361 {RPCResult::Type::NUM, "threshold", /*optional=*/true, "the number of blocks with the version bit set required to activate the feature (only for \"started\" status)"},
1362 {RPCResult::Type::NUM, "elapsed", "the number of blocks elapsed since the beginning of the current period"},
1363 {RPCResult::Type::NUM, "count", "the number of blocks with the version bit set in the current period"},
1364 {RPCResult::Type::BOOL, "possible", /*optional=*/true, "returns false if there are not enough blocks left in this period to pass activation threshold (only for \"started\" status)"},
1365 }},
1366 {RPCResult::Type::STR, "signalling", /*optional=*/true, "indicates blocks that signalled with a # and blocks that did not with a -"},
1367 }},
1368};
1369
1370UniValue DeploymentInfo(const CBlockIndex* blockindex, const ChainstateManager& chainman)
1371{
1372 UniValue softforks(UniValue::VOBJ);
1373 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_HEIGHTINCB);
1374 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_DERSIG);
1375 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_CLTV);
1376 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_CSV);
1377 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_SEGWIT);
1378 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TESTDUMMY);
1379 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TAPROOT);
1380 return softforks;
1381}
1382} // anon namespace
1383
1385{
1386 return RPCHelpMan{"getdeploymentinfo",
1387 "Returns an object containing various state info regarding deployments of consensus changes.",
1388 {
1389 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Default{"hash of current chain tip"}, "The block hash at which to query deployment state"},
1390 },
1391 RPCResult{
1392 RPCResult::Type::OBJ, "", "", {
1393 {RPCResult::Type::STR, "hash", "requested block hash (or tip)"},
1394 {RPCResult::Type::NUM, "height", "requested block height (or tip)"},
1395 {RPCResult::Type::OBJ_DYN, "deployments", "", {
1396 {RPCResult::Type::OBJ, "xxxx", "name of the deployment", RPCHelpForDeployment}
1397 }},
1398 }
1399 },
1400 RPCExamples{ HelpExampleCli("getdeploymentinfo", "") + HelpExampleRpc("getdeploymentinfo", "") },
1401 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1402 {
1403 const ChainstateManager& chainman = EnsureAnyChainman(request.context);
1404 LOCK(cs_main);
1405 const Chainstate& active_chainstate = chainman.ActiveChainstate();
1406
1407 const CBlockIndex* blockindex;
1408 if (request.params[0].isNull()) {
1409 blockindex = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
1410 } else {
1411 const uint256 hash(ParseHashV(request.params[0], "blockhash"));
1412 blockindex = chainman.m_blockman.LookupBlockIndex(hash);
1413 if (!blockindex) {
1414 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1415 }
1416 }
1417
1418 UniValue deploymentinfo(UniValue::VOBJ);
1419 deploymentinfo.pushKV("hash", blockindex->GetBlockHash().ToString());
1420 deploymentinfo.pushKV("height", blockindex->nHeight);
1421 deploymentinfo.pushKV("deployments", DeploymentInfo(blockindex, chainman));
1422 return deploymentinfo;
1423 },
1424 };
1425}
1426
1429{
1430 bool operator()(const CBlockIndex* a, const CBlockIndex* b) const
1431 {
1432 /* Make sure that unequal blocks with the same height do not compare
1433 equal. Use the pointers themselves to make a distinction. */
1434
1435 if (a->nHeight != b->nHeight)
1436 return (a->nHeight > b->nHeight);
1437
1438 return a < b;
1439 }
1440};
1441
1443{
1444 return RPCHelpMan{"getchaintips",
1445 "Return information about all known tips in the block tree,"
1446 " including the main chain as well as orphaned branches.\n",
1447 {},
1448 RPCResult{
1449 RPCResult::Type::ARR, "", "",
1450 {{RPCResult::Type::OBJ, "", "",
1451 {
1452 {RPCResult::Type::NUM, "height", "height of the chain tip"},
1453 {RPCResult::Type::STR_HEX, "hash", "block hash of the tip"},
1454 {RPCResult::Type::NUM, "branchlen", "zero for main chain, otherwise length of branch connecting the tip to the main chain"},
1455 {RPCResult::Type::STR, "status", "status of the chain, \"active\" for the main chain\n"
1456 "Possible values for status:\n"
1457 "1. \"invalid\" This branch contains at least one invalid block\n"
1458 "2. \"headers-only\" Not all blocks for this branch are available, but the headers are valid\n"
1459 "3. \"valid-headers\" All blocks are available for this branch, but they were never fully validated\n"
1460 "4. \"valid-fork\" This branch is not part of the active chain, but is fully validated\n"
1461 "5. \"active\" This is the tip of the active main chain, which is certainly valid"},
1462 }}}},
1464 HelpExampleCli("getchaintips", "")
1465 + HelpExampleRpc("getchaintips", "")
1466 },
1467 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1468{
1469 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1470 LOCK(cs_main);
1471 CChain& active_chain = chainman.ActiveChain();
1472
1473 /*
1474 * Idea: The set of chain tips is the active chain tip, plus orphan blocks which do not have another orphan building off of them.
1475 * Algorithm:
1476 * - Make one pass through BlockIndex(), picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers.
1477 * - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip.
1478 * - Add the active chain tip
1479 */
1480 std::set<const CBlockIndex*, CompareBlocksByHeight> setTips;
1481 std::set<const CBlockIndex*> setOrphans;
1482 std::set<const CBlockIndex*> setPrevs;
1483
1484 for (const auto& [_, block_index] : chainman.BlockIndex()) {
1485 if (!active_chain.Contains(&block_index)) {
1486 setOrphans.insert(&block_index);
1487 setPrevs.insert(block_index.pprev);
1488 }
1489 }
1490
1491 for (std::set<const CBlockIndex*>::iterator it = setOrphans.begin(); it != setOrphans.end(); ++it) {
1492 if (setPrevs.erase(*it) == 0) {
1493 setTips.insert(*it);
1494 }
1495 }
1496
1497 // Always report the currently active tip.
1498 setTips.insert(active_chain.Tip());
1499
1500 /* Construct the output array. */
1502 for (const CBlockIndex* block : setTips) {
1504 obj.pushKV("height", block->nHeight);
1505 obj.pushKV("hash", block->phashBlock->GetHex());
1506
1507 const int branchLen = block->nHeight - active_chain.FindFork(block)->nHeight;
1508 obj.pushKV("branchlen", branchLen);
1509
1510 std::string status;
1511 if (active_chain.Contains(block)) {
1512 // This block is part of the currently active chain.
1513 status = "active";
1514 } else if (block->nStatus & BLOCK_FAILED_MASK) {
1515 // This block or one of its ancestors is invalid.
1516 status = "invalid";
1517 } else if (!block->HaveNumChainTxs()) {
1518 // This block cannot be connected because full block data for it or one of its parents is missing.
1519 status = "headers-only";
1520 } else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {
1521 // This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.
1522 status = "valid-fork";
1523 } else if (block->IsValid(BLOCK_VALID_TREE)) {
1524 // The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.
1525 status = "valid-headers";
1526 } else {
1527 // No clue.
1528 status = "unknown";
1529 }
1530 obj.pushKV("status", status);
1531
1532 res.push_back(std::move(obj));
1533 }
1534
1535 return res;
1536},
1537 };
1538}
1539
1541{
1542 return RPCHelpMan{"preciousblock",
1543 "\nTreats a block as if it were received before others with the same work.\n"
1544 "\nA later preciousblock call can override the effect of an earlier one.\n"
1545 "\nThe effects of preciousblock are not retained across restarts.\n",
1546 {
1547 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as precious"},
1548 },
1551 HelpExampleCli("preciousblock", "\"blockhash\"")
1552 + HelpExampleRpc("preciousblock", "\"blockhash\"")
1553 },
1554 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1555{
1556 uint256 hash(ParseHashV(request.params[0], "blockhash"));
1557 CBlockIndex* pblockindex;
1558
1559 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1560 {
1561 LOCK(cs_main);
1562 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1563 if (!pblockindex) {
1564 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1565 }
1566 }
1567
1569 chainman.ActiveChainstate().PreciousBlock(state, pblockindex);
1570
1571 if (!state.IsValid()) {
1573 }
1574
1575 return UniValue::VNULL;
1576},
1577 };
1578}
1579
1581{
1582 return RPCHelpMan{"invalidateblock",
1583 "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n",
1584 {
1585 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as invalid"},
1586 },
1589 HelpExampleCli("invalidateblock", "\"blockhash\"")
1590 + HelpExampleRpc("invalidateblock", "\"blockhash\"")
1591 },
1592 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1593{
1594 uint256 hash(ParseHashV(request.params[0], "blockhash"));
1596
1597 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1598 CBlockIndex* pblockindex;
1599 {
1600 LOCK(cs_main);
1601 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1602 if (!pblockindex) {
1603 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1604 }
1605 }
1606 chainman.ActiveChainstate().InvalidateBlock(state, pblockindex);
1607
1608 if (state.IsValid()) {
1609 chainman.ActiveChainstate().ActivateBestChain(state);
1610 }
1611
1612 if (!state.IsValid()) {
1614 }
1615
1616 return UniValue::VNULL;
1617},
1618 };
1619}
1620
1622{
1623 return RPCHelpMan{"reconsiderblock",
1624 "\nRemoves invalidity status of a block, its ancestors and its descendants, reconsider them for activation.\n"
1625 "This can be used to undo the effects of invalidateblock.\n",
1626 {
1627 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to reconsider"},
1628 },
1631 HelpExampleCli("reconsiderblock", "\"blockhash\"")
1632 + HelpExampleRpc("reconsiderblock", "\"blockhash\"")
1633 },
1634 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1635{
1636 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1637 uint256 hash(ParseHashV(request.params[0], "blockhash"));
1638
1639 {
1640 LOCK(cs_main);
1641 CBlockIndex* pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1642 if (!pblockindex) {
1643 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1644 }
1645
1646 chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex);
1647 }
1648
1650 chainman.ActiveChainstate().ActivateBestChain(state);
1651
1652 if (!state.IsValid()) {
1654 }
1655
1656 return UniValue::VNULL;
1657},
1658 };
1659}
1660
1662{
1663 return RPCHelpMan{"getchaintxstats",
1664 "\nCompute statistics about the total number and rate of transactions in the chain.\n",
1665 {
1666 {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{"one month"}, "Size of the window in number of blocks"},
1667 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"chain tip"}, "The hash of the block that ends the window."},
1668 },
1669 RPCResult{
1670 RPCResult::Type::OBJ, "", "",
1671 {
1672 {RPCResult::Type::NUM_TIME, "time", "The timestamp for the final block in the window, expressed in " + UNIX_EPOCH_TIME},
1673 {RPCResult::Type::NUM, "txcount", /*optional=*/true,
1674 "The total number of transactions in the chain up to that point, if known. "
1675 "It may be unknown when using assumeutxo."},
1676 {RPCResult::Type::STR_HEX, "window_final_block_hash", "The hash of the final block in the window"},
1677 {RPCResult::Type::NUM, "window_final_block_height", "The height of the final block in the window."},
1678 {RPCResult::Type::NUM, "window_block_count", "Size of the window in number of blocks"},
1679 {RPCResult::Type::NUM, "window_interval", /*optional=*/true, "The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0"},
1680 {RPCResult::Type::NUM, "window_tx_count", /*optional=*/true,
1681 "The number of transactions in the window. "
1682 "Only returned if \"window_block_count\" is > 0 and if txcount exists for the start and end of the window."},
1683 {RPCResult::Type::NUM, "txrate", /*optional=*/true,
1684 "The average rate of transactions per second in the window. "
1685 "Only returned if \"window_interval\" is > 0 and if window_tx_count exists."},
1686 }},
1688 HelpExampleCli("getchaintxstats", "")
1689 + HelpExampleRpc("getchaintxstats", "2016")
1690 },
1691 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1692{
1693 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1694 const CBlockIndex* pindex;
1695 int blockcount = 30 * 24 * 60 * 60 / chainman.GetParams().GetConsensus().nPowTargetSpacing; // By default: 1 month
1696
1697 if (request.params[1].isNull()) {
1698 LOCK(cs_main);
1699 pindex = chainman.ActiveChain().Tip();
1700 } else {
1701 uint256 hash(ParseHashV(request.params[1], "blockhash"));
1702 LOCK(cs_main);
1703 pindex = chainman.m_blockman.LookupBlockIndex(hash);
1704 if (!pindex) {
1705 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1706 }
1707 if (!chainman.ActiveChain().Contains(pindex)) {
1708 throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain");
1709 }
1710 }
1711
1712 CHECK_NONFATAL(pindex != nullptr);
1713
1714 if (request.params[0].isNull()) {
1715 blockcount = std::max(0, std::min(blockcount, pindex->nHeight - 1));
1716 } else {
1717 blockcount = request.params[0].getInt<int>();
1718
1719 if (blockcount < 0 || (blockcount > 0 && blockcount >= pindex->nHeight)) {
1720 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 0 and the block's height - 1");
1721 }
1722 }
1723
1724 const CBlockIndex& past_block{*CHECK_NONFATAL(pindex->GetAncestor(pindex->nHeight - blockcount))};
1725 const int64_t nTimeDiff{pindex->GetMedianTimePast() - past_block.GetMedianTimePast()};
1726
1728 ret.pushKV("time", (int64_t)pindex->nTime);
1729 if (pindex->m_chain_tx_count) {
1730 ret.pushKV("txcount", pindex->m_chain_tx_count);
1731 }
1732 ret.pushKV("window_final_block_hash", pindex->GetBlockHash().GetHex());
1733 ret.pushKV("window_final_block_height", pindex->nHeight);
1734 ret.pushKV("window_block_count", blockcount);
1735 if (blockcount > 0) {
1736 ret.pushKV("window_interval", nTimeDiff);
1737 if (pindex->m_chain_tx_count != 0 && past_block.m_chain_tx_count != 0) {
1738 const auto window_tx_count = pindex->m_chain_tx_count - past_block.m_chain_tx_count;
1739 ret.pushKV("window_tx_count", window_tx_count);
1740 if (nTimeDiff > 0) {
1741 ret.pushKV("txrate", double(window_tx_count) / nTimeDiff);
1742 }
1743 }
1744 }
1745
1746 return ret;
1747},
1748 };
1749}
1750
1751template<typename T>
1752static T CalculateTruncatedMedian(std::vector<T>& scores)
1753{
1754 size_t size = scores.size();
1755 if (size == 0) {
1756 return 0;
1757 }
1758
1759 std::sort(scores.begin(), scores.end());
1760 if (size % 2 == 0) {
1761 return (scores[size / 2 - 1] + scores[size / 2]) / 2;
1762 } else {
1763 return scores[size / 2];
1764 }
1765}
1766
1767void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight)
1768{
1769 if (scores.empty()) {
1770 return;
1771 }
1772
1773 std::sort(scores.begin(), scores.end());
1774
1775 // 10th, 25th, 50th, 75th, and 90th percentile weight units.
1776 const double weights[NUM_GETBLOCKSTATS_PERCENTILES] = {
1777 total_weight / 10.0, total_weight / 4.0, total_weight / 2.0, (total_weight * 3.0) / 4.0, (total_weight * 9.0) / 10.0
1778 };
1779
1780 int64_t next_percentile_index = 0;
1781 int64_t cumulative_weight = 0;
1782 for (const auto& element : scores) {
1783 cumulative_weight += element.second;
1784 while (next_percentile_index < NUM_GETBLOCKSTATS_PERCENTILES && cumulative_weight >= weights[next_percentile_index]) {
1785 result[next_percentile_index] = element.first;
1786 ++next_percentile_index;
1787 }
1788 }
1789
1790 // Fill any remaining percentiles with the last value.
1791 for (int64_t i = next_percentile_index; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {
1792 result[i] = scores.back().first;
1793 }
1794}
1795
1796template<typename T>
1797static inline bool SetHasKeys(const std::set<T>& set) {return false;}
1798template<typename T, typename Tk, typename... Args>
1799static inline bool SetHasKeys(const std::set<T>& set, const Tk& key, const Args&... args)
1800{
1801 return (set.count(key) != 0) || SetHasKeys(set, args...);
1802}
1803
1804// outpoint (needed for the utxo index) + nHeight + fCoinBase
1805static constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);
1806
1808{
1809 return RPCHelpMan{"getblockstats",
1810 "\nCompute per block statistics for a given window. All amounts are in satoshis.\n"
1811 "It won't work for some heights with pruning.\n",
1812 {
1813 {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block",
1815 .skip_type_check = true,
1816 .type_str = {"", "string or numeric"},
1817 }},
1818 {"stats", RPCArg::Type::ARR, RPCArg::DefaultHint{"all values"}, "Values to plot (see result below)",
1819 {
1820 {"height", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
1821 {"time", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
1822 },
1823 RPCArgOptions{.oneline_description="stats"}},
1824 },
1825 RPCResult{
1826 RPCResult::Type::OBJ, "", "",
1827 {
1828 {RPCResult::Type::NUM, "avgfee", /*optional=*/true, "Average fee in the block"},
1829 {RPCResult::Type::NUM, "avgfeerate", /*optional=*/true, "Average feerate (in satoshis per virtual byte)"},
1830 {RPCResult::Type::NUM, "avgtxsize", /*optional=*/true, "Average transaction size"},
1831 {RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "The block hash (to check for potential reorgs)"},
1832 {RPCResult::Type::ARR_FIXED, "feerate_percentiles", /*optional=*/true, "Feerates at the 10th, 25th, 50th, 75th, and 90th percentile weight unit (in satoshis per virtual byte)",
1833 {
1834 {RPCResult::Type::NUM, "10th_percentile_feerate", "The 10th percentile feerate"},
1835 {RPCResult::Type::NUM, "25th_percentile_feerate", "The 25th percentile feerate"},
1836 {RPCResult::Type::NUM, "50th_percentile_feerate", "The 50th percentile feerate"},
1837 {RPCResult::Type::NUM, "75th_percentile_feerate", "The 75th percentile feerate"},
1838 {RPCResult::Type::NUM, "90th_percentile_feerate", "The 90th percentile feerate"},
1839 }},
1840 {RPCResult::Type::NUM, "height", /*optional=*/true, "The height of the block"},
1841 {RPCResult::Type::NUM, "ins", /*optional=*/true, "The number of inputs (excluding coinbase)"},
1842 {RPCResult::Type::NUM, "maxfee", /*optional=*/true, "Maximum fee in the block"},
1843 {RPCResult::Type::NUM, "maxfeerate", /*optional=*/true, "Maximum feerate (in satoshis per virtual byte)"},
1844 {RPCResult::Type::NUM, "maxtxsize", /*optional=*/true, "Maximum transaction size"},
1845 {RPCResult::Type::NUM, "medianfee", /*optional=*/true, "Truncated median fee in the block"},
1846 {RPCResult::Type::NUM, "mediantime", /*optional=*/true, "The block median time past"},
1847 {RPCResult::Type::NUM, "mediantxsize", /*optional=*/true, "Truncated median transaction size"},
1848 {RPCResult::Type::NUM, "minfee", /*optional=*/true, "Minimum fee in the block"},
1849 {RPCResult::Type::NUM, "minfeerate", /*optional=*/true, "Minimum feerate (in satoshis per virtual byte)"},
1850 {RPCResult::Type::NUM, "mintxsize", /*optional=*/true, "Minimum transaction size"},
1851 {RPCResult::Type::NUM, "outs", /*optional=*/true, "The number of outputs"},
1852 {RPCResult::Type::NUM, "subsidy", /*optional=*/true, "The block subsidy"},
1853 {RPCResult::Type::NUM, "swtotal_size", /*optional=*/true, "Total size of all segwit transactions"},
1854 {RPCResult::Type::NUM, "swtotal_weight", /*optional=*/true, "Total weight of all segwit transactions"},
1855 {RPCResult::Type::NUM, "swtxs", /*optional=*/true, "The number of segwit transactions"},
1856 {RPCResult::Type::NUM, "time", /*optional=*/true, "The block time"},
1857 {RPCResult::Type::NUM, "total_out", /*optional=*/true, "Total amount in all outputs (excluding coinbase and thus reward [ie subsidy + totalfee])"},
1858 {RPCResult::Type::NUM, "total_size", /*optional=*/true, "Total size of all non-coinbase transactions"},
1859 {RPCResult::Type::NUM, "total_weight", /*optional=*/true, "Total weight of all non-coinbase transactions"},
1860 {RPCResult::Type::NUM, "totalfee", /*optional=*/true, "The fee total"},
1861 {RPCResult::Type::NUM, "txs", /*optional=*/true, "The number of transactions (including coinbase)"},
1862 {RPCResult::Type::NUM, "utxo_increase", /*optional=*/true, "The increase/decrease in the number of unspent outputs (not discounting op_return and similar)"},
1863 {RPCResult::Type::NUM, "utxo_size_inc", /*optional=*/true, "The increase/decrease in size for the utxo index (not discounting op_return and similar)"},
1864 {RPCResult::Type::NUM, "utxo_increase_actual", /*optional=*/true, "The increase/decrease in the number of unspent outputs, not counting unspendables"},
1865 {RPCResult::Type::NUM, "utxo_size_inc_actual", /*optional=*/true, "The increase/decrease in size for the utxo index, not counting unspendables"},
1866 }},
1868 HelpExampleCli("getblockstats", R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
1869 HelpExampleCli("getblockstats", R"(1000 '["minfeerate","avgfeerate"]')") +
1870 HelpExampleRpc("getblockstats", R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") +
1871 HelpExampleRpc("getblockstats", R"(1000, ["minfeerate","avgfeerate"])")
1872 },
1873 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1874{
1875 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1876 const CBlockIndex& pindex{*CHECK_NONFATAL(ParseHashOrHeight(request.params[0], chainman))};
1877
1878 std::set<std::string> stats;
1879 if (!request.params[1].isNull()) {
1880 const UniValue stats_univalue = request.params[1].get_array();
1881 for (unsigned int i = 0; i < stats_univalue.size(); i++) {
1882 const std::string stat = stats_univalue[i].get_str();
1883 stats.insert(stat);
1884 }
1885 }
1886
1887 const CBlock& block = GetBlockChecked(chainman.m_blockman, pindex);
1888 const CBlockUndo& blockUndo = GetUndoChecked(chainman.m_blockman, pindex);
1889
1890 const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default)
1891 const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0;
1892 const bool do_medianfee = do_all || stats.count("medianfee") != 0;
1893 const bool do_feerate_percentiles = do_all || stats.count("feerate_percentiles") != 0;
1894 const bool loop_inputs = do_all || do_medianfee || do_feerate_percentiles ||
1895 SetHasKeys(stats, "utxo_increase", "utxo_increase_actual", "utxo_size_inc", "utxo_size_inc_actual", "totalfee", "avgfee", "avgfeerate", "minfee", "maxfee", "minfeerate", "maxfeerate");
1896 const bool loop_outputs = do_all || loop_inputs || stats.count("total_out");
1897 const bool do_calculate_size = do_mediantxsize ||
1898 SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize", "maxtxsize", "swtotal_size");
1899 const bool do_calculate_weight = do_all || SetHasKeys(stats, "total_weight", "avgfeerate", "swtotal_weight", "avgfeerate", "feerate_percentiles", "minfeerate", "maxfeerate");
1900 const bool do_calculate_sw = do_all || SetHasKeys(stats, "swtxs", "swtotal_size", "swtotal_weight");
1901
1902 CAmount maxfee = 0;
1903 CAmount maxfeerate = 0;
1904 CAmount minfee = MAX_MONEY;
1905 CAmount minfeerate = MAX_MONEY;
1906 CAmount total_out = 0;
1907 CAmount totalfee = 0;
1908 int64_t inputs = 0;
1909 int64_t maxtxsize = 0;
1910 int64_t mintxsize = MAX_BLOCK_SERIALIZED_SIZE;
1911 int64_t outputs = 0;
1912 int64_t swtotal_size = 0;
1913 int64_t swtotal_weight = 0;
1914 int64_t swtxs = 0;
1915 int64_t total_size = 0;
1916 int64_t total_weight = 0;
1917 int64_t utxos = 0;
1918 int64_t utxo_size_inc = 0;
1919 int64_t utxo_size_inc_actual = 0;
1920 std::vector<CAmount> fee_array;
1921 std::vector<std::pair<CAmount, int64_t>> feerate_array;
1922 std::vector<int64_t> txsize_array;
1923
1924 for (size_t i = 0; i < block.vtx.size(); ++i) {
1925 const auto& tx = block.vtx.at(i);
1926 outputs += tx->vout.size();
1927
1928 CAmount tx_total_out = 0;
1929 if (loop_outputs) {
1930 for (const CTxOut& out : tx->vout) {
1931 tx_total_out += out.nValue;
1932
1933 size_t out_size = GetSerializeSize(out) + PER_UTXO_OVERHEAD;
1934 utxo_size_inc += out_size;
1935
1936 // The Genesis block and the repeated BIP30 block coinbases don't change the UTXO
1937 // set counts, so they have to be excluded from the statistics
1938 if (pindex.nHeight == 0 || (IsBIP30Repeat(pindex) && tx->IsCoinBase())) continue;
1939 // Skip unspendable outputs since they are not included in the UTXO set
1940 if (out.scriptPubKey.IsUnspendable()) continue;
1941
1942 ++utxos;
1943 utxo_size_inc_actual += out_size;
1944 }
1945 }
1946
1947 if (tx->IsCoinBase()) {
1948 continue;
1949 }
1950
1951 inputs += tx->vin.size(); // Don't count coinbase's fake input
1952 total_out += tx_total_out; // Don't count coinbase reward
1953
1954 int64_t tx_size = 0;
1955 if (do_calculate_size) {
1956
1957 tx_size = tx->GetTotalSize();
1958 if (do_mediantxsize) {
1959 txsize_array.push_back(tx_size);
1960 }
1961 maxtxsize = std::max(maxtxsize, tx_size);
1962 mintxsize = std::min(mintxsize, tx_size);
1963 total_size += tx_size;
1964 }
1965
1966 int64_t weight = 0;
1967 if (do_calculate_weight) {
1968 weight = GetTransactionWeight(*tx);
1969 total_weight += weight;
1970 }
1971
1972 if (do_calculate_sw && tx->HasWitness()) {
1973 ++swtxs;
1974 swtotal_size += tx_size;
1975 swtotal_weight += weight;
1976 }
1977
1978 if (loop_inputs) {
1979 CAmount tx_total_in = 0;
1980 const auto& txundo = blockUndo.vtxundo.at(i - 1);
1981 for (const Coin& coin: txundo.vprevout) {
1982 const CTxOut& prevoutput = coin.out;
1983
1984 tx_total_in += prevoutput.nValue;
1985 size_t prevout_size = GetSerializeSize(prevoutput) + PER_UTXO_OVERHEAD;
1986 utxo_size_inc -= prevout_size;
1987 utxo_size_inc_actual -= prevout_size;
1988 }
1989
1990 CAmount txfee = tx_total_in - tx_total_out;
1991 CHECK_NONFATAL(MoneyRange(txfee));
1992 if (do_medianfee) {
1993 fee_array.push_back(txfee);
1994 }
1995 maxfee = std::max(maxfee, txfee);
1996 minfee = std::min(minfee, txfee);
1997 totalfee += txfee;
1998
1999 // New feerate uses satoshis per virtual byte instead of per serialized byte
2000 CAmount feerate = weight ? (txfee * WITNESS_SCALE_FACTOR) / weight : 0;
2001 if (do_feerate_percentiles) {
2002 feerate_array.emplace_back(feerate, weight);
2003 }
2004 maxfeerate = std::max(maxfeerate, feerate);
2005 minfeerate = std::min(minfeerate, feerate);
2006 }
2007 }
2008
2009 CAmount feerate_percentiles[NUM_GETBLOCKSTATS_PERCENTILES] = { 0 };
2010 CalculatePercentilesByWeight(feerate_percentiles, feerate_array, total_weight);
2011
2012 UniValue feerates_res(UniValue::VARR);
2013 for (int64_t i = 0; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {
2014 feerates_res.push_back(feerate_percentiles[i]);
2015 }
2016
2017 UniValue ret_all(UniValue::VOBJ);
2018 ret_all.pushKV("avgfee", (block.vtx.size() > 1) ? totalfee / (block.vtx.size() - 1) : 0);
2019 ret_all.pushKV("avgfeerate", total_weight ? (totalfee * WITNESS_SCALE_FACTOR) / total_weight : 0); // Unit: sat/vbyte
2020 ret_all.pushKV("avgtxsize", (block.vtx.size() > 1) ? total_size / (block.vtx.size() - 1) : 0);
2021 ret_all.pushKV("blockhash", pindex.GetBlockHash().GetHex());
2022 ret_all.pushKV("feerate_percentiles", std::move(feerates_res));
2023 ret_all.pushKV("height", (int64_t)pindex.nHeight);
2024 ret_all.pushKV("ins", inputs);
2025 ret_all.pushKV("maxfee", maxfee);
2026 ret_all.pushKV("maxfeerate", maxfeerate);
2027 ret_all.pushKV("maxtxsize", maxtxsize);
2028 ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
2029 ret_all.pushKV("mediantime", pindex.GetMedianTimePast());
2030 ret_all.pushKV("mediantxsize", CalculateTruncatedMedian(txsize_array));
2031 ret_all.pushKV("minfee", (minfee == MAX_MONEY) ? 0 : minfee);
2032 ret_all.pushKV("minfeerate", (minfeerate == MAX_MONEY) ? 0 : minfeerate);
2033 ret_all.pushKV("mintxsize", mintxsize == MAX_BLOCK_SERIALIZED_SIZE ? 0 : mintxsize);
2034 ret_all.pushKV("outs", outputs);
2035 ret_all.pushKV("subsidy", GetBlockSubsidy(pindex.nHeight, chainman.GetParams().GetConsensus()));
2036 ret_all.pushKV("swtotal_size", swtotal_size);
2037 ret_all.pushKV("swtotal_weight", swtotal_weight);
2038 ret_all.pushKV("swtxs", swtxs);
2039 ret_all.pushKV("time", pindex.GetBlockTime());
2040 ret_all.pushKV("total_out", total_out);
2041 ret_all.pushKV("total_size", total_size);
2042 ret_all.pushKV("total_weight", total_weight);
2043 ret_all.pushKV("totalfee", totalfee);
2044 ret_all.pushKV("txs", (int64_t)block.vtx.size());
2045 ret_all.pushKV("utxo_increase", outputs - inputs);
2046 ret_all.pushKV("utxo_size_inc", utxo_size_inc);
2047 ret_all.pushKV("utxo_increase_actual", utxos - inputs);
2048 ret_all.pushKV("utxo_size_inc_actual", utxo_size_inc_actual);
2049
2050 if (do_all) {
2051 return ret_all;
2052 }
2053
2055 for (const std::string& stat : stats) {
2056 const UniValue& value = ret_all[stat];
2057 if (value.isNull()) {
2058 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid selected statistic '%s'", stat));
2059 }
2060 ret.pushKV(stat, value);
2061 }
2062 return ret;
2063},
2064 };
2065}
2066
2067namespace {
2069bool FindScriptPubKey(std::atomic<int>& scan_progress, const std::atomic<bool>& should_abort, int64_t& count, CCoinsViewCursor* cursor, const std::set<CScript>& needles, std::map<COutPoint, Coin>& out_results, std::function<void()>& interruption_point)
2070{
2071 scan_progress = 0;
2072 count = 0;
2073 while (cursor->Valid()) {
2074 COutPoint key;
2075 Coin coin;
2076 if (!cursor->GetKey(key) || !cursor->GetValue(coin)) return false;
2077 if (++count % 8192 == 0) {
2078 interruption_point();
2079 if (should_abort) {
2080 // allow to abort the scan via the abort reference
2081 return false;
2082 }
2083 }
2084 if (count % 256 == 0) {
2085 // update progress reference every 256 item
2086 uint32_t high = 0x100 * *UCharCast(key.hash.begin()) + *(UCharCast(key.hash.begin()) + 1);
2087 scan_progress = (int)(high * 100.0 / 65536.0 + 0.5);
2088 }
2089 if (needles.count(coin.out.scriptPubKey)) {
2090 out_results.emplace(key, coin);
2091 }
2092 cursor->Next();
2093 }
2094 scan_progress = 100;
2095 return true;
2096}
2097} // namespace
2098
2100static std::atomic<int> g_scan_progress;
2101static std::atomic<bool> g_scan_in_progress;
2102static std::atomic<bool> g_should_abort_scan;
2104{
2105private:
2106 bool m_could_reserve{false};
2107public:
2108 explicit CoinsViewScanReserver() = default;
2109
2110 bool reserve() {
2112 if (g_scan_in_progress.exchange(true)) {
2113 return false;
2114 }
2116 m_could_reserve = true;
2117 return true;
2118 }
2119
2121 if (m_could_reserve) {
2122 g_scan_in_progress = false;
2123 g_scan_progress = 0;
2124 }
2125 }
2126};
2127
2128static const auto scan_action_arg_desc = RPCArg{
2129 "action", RPCArg::Type::STR, RPCArg::Optional::NO, "The action to execute\n"
2130 "\"start\" for starting a scan\n"
2131 "\"abort\" for aborting the current scan (returns true when abort was successful)\n"
2132 "\"status\" for progress report (in %) of the current scan"
2133};
2134
2135static const auto scan_objects_arg_desc = RPCArg{
2136 "scanobjects", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "Array of scan objects. Required for \"start\" action\n"
2137 "Every scan object is either a string descriptor or an object:",
2138 {
2139 {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
2140 {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with output descriptor and metadata",
2141 {
2142 {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
2143 {"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "The range of HD chain indexes to explore (either end or [begin,end])"},
2144 }},
2145 },
2146 RPCArgOptions{.oneline_description="[scanobjects,...]"},
2147};
2148
2149static const auto scan_result_abort = RPCResult{
2150 "when action=='abort'", RPCResult::Type::BOOL, "success",
2151 "True if scan will be aborted (not necessarily before this RPC returns), or false if there is no scan to abort"
2152};
2154 "when action=='status' and no scan is in progress - possibly already completed", RPCResult::Type::NONE, "", ""
2155};
2157 "when action=='status' and a scan is currently in progress", RPCResult::Type::OBJ, "", "",
2158 {{RPCResult::Type::NUM, "progress", "Approximate percent complete"},}
2159};
2160
2161
2163{
2164 // raw() descriptor corresponding to mainnet address 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S
2165 const std::string EXAMPLE_DESCRIPTOR_RAW = "raw(76a91411b366edfc0a8b66feebae5c2e25a7b6a5d1cf3188ac)#fm24fxxy";
2166
2167 return RPCHelpMan{"scantxoutset",
2168 "\nScans the unspent transaction output set for entries that match certain output descriptors.\n"
2169 "Examples of output descriptors are:\n"
2170 " addr(<address>) Outputs whose output script corresponds to the specified address (does not include P2PK)\n"
2171 " raw(<hex script>) Outputs whose output script equals the specified hex-encoded bytes\n"
2172 " combo(<pubkey>) P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH outputs for the given pubkey\n"
2173 " pkh(<pubkey>) P2PKH outputs for the given pubkey\n"
2174 " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n"
2175 " tr(<pubkey>) P2TR\n"
2176 " tr(<pubkey>,{pk(<pubkey>)}) P2TR with single fallback pubkey in tapscript\n"
2177 " rawtr(<pubkey>) P2TR with the specified key as output key rather than inner\n"
2178 " wsh(and_v(v:pk(<pubkey>),after(2))) P2WSH miniscript with mandatory pubkey and a timelock\n"
2179 "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
2180 "or more path elements separated by \"/\", and optionally ending in \"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
2181 "unhardened or hardened child keys.\n"
2182 "In the latter case, a range needs to be specified by below if different from 1000.\n"
2183 "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n",
2184 {
2187 },
2188 {
2189 RPCResult{"when action=='start'; only returns after scan completes", RPCResult::Type::OBJ, "", "", {
2190 {RPCResult::Type::BOOL, "success", "Whether the scan was completed"},
2191 {RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs scanned"},
2192 {RPCResult::Type::NUM, "height", "The block height at which the scan was done"},
2193 {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
2194 {RPCResult::Type::ARR, "unspents", "",
2195 {
2196 {RPCResult::Type::OBJ, "", "",
2197 {
2198 {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
2199 {RPCResult::Type::NUM, "vout", "The vout value"},
2200 {RPCResult::Type::STR_HEX, "scriptPubKey", "The output script"},
2201 {RPCResult::Type::STR, "desc", "A specialized descriptor for the matched output script"},
2202 {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the unspent output"},
2203 {RPCResult::Type::BOOL, "coinbase", "Whether this is a coinbase output"},
2204 {RPCResult::Type::NUM, "height", "Height of the unspent transaction output"},
2205 {RPCResult::Type::STR_HEX, "blockhash", "Blockhash of the unspent transaction output"},
2206 {RPCResult::Type::NUM, "confirmations", "Number of confirmations of the unspent transaction output when the scan was done"},
2207 }},
2208 }},
2209 {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of all found unspent outputs in " + CURRENCY_UNIT},
2210 }},
2214 },
2216 HelpExampleCli("scantxoutset", "start \'[\"" + EXAMPLE_DESCRIPTOR_RAW + "\"]\'") +
2217 HelpExampleCli("scantxoutset", "status") +
2218 HelpExampleCli("scantxoutset", "abort") +
2219 HelpExampleRpc("scantxoutset", "\"start\", [\"" + EXAMPLE_DESCRIPTOR_RAW + "\"]") +
2220 HelpExampleRpc("scantxoutset", "\"status\"") +
2221 HelpExampleRpc("scantxoutset", "\"abort\"")
2222 },
2223 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2224{
2225 UniValue result(UniValue::VOBJ);
2226 const auto action{self.Arg<std::string>("action")};
2227 if (action == "status") {
2228 CoinsViewScanReserver reserver;
2229 if (reserver.reserve()) {
2230 // no scan in progress
2231 return UniValue::VNULL;
2232 }
2233 result.pushKV("progress", g_scan_progress.load());
2234 return result;
2235 } else if (action == "abort") {
2236 CoinsViewScanReserver reserver;
2237 if (reserver.reserve()) {
2238 // reserve was possible which means no scan was running
2239 return false;
2240 }
2241 // set the abort flag
2242 g_should_abort_scan = true;
2243 return true;
2244 } else if (action == "start") {
2245 CoinsViewScanReserver reserver;
2246 if (!reserver.reserve()) {
2247 throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
2248 }
2249
2250 if (request.params.size() < 2) {
2251 throw JSONRPCError(RPC_MISC_ERROR, "scanobjects argument is required for the start action");
2252 }
2253
2254 std::set<CScript> needles;
2255 std::map<CScript, std::string> descriptors;
2256 CAmount total_in = 0;
2257
2258 // loop through the scan objects
2259 for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
2260 FlatSigningProvider provider;
2261 auto scripts = EvalDescriptorStringOrObject(scanobject, provider);
2262 for (CScript& script : scripts) {
2263 std::string inferred = InferDescriptor(script, provider)->ToString();
2264 needles.emplace(script);
2265 descriptors.emplace(std::move(script), std::move(inferred));
2266 }
2267 }
2268
2269 // Scan the unspent transaction output set for inputs
2270 UniValue unspents(UniValue::VARR);
2271 std::vector<CTxOut> input_txos;
2272 std::map<COutPoint, Coin> coins;
2273 g_should_abort_scan = false;
2274 int64_t count = 0;
2275 std::unique_ptr<CCoinsViewCursor> pcursor;
2276 const CBlockIndex* tip;
2277 NodeContext& node = EnsureAnyNodeContext(request.context);
2278 {
2280 LOCK(cs_main);
2281 Chainstate& active_chainstate = chainman.ActiveChainstate();
2282 active_chainstate.ForceFlushStateToDisk();
2283 pcursor = CHECK_NONFATAL(active_chainstate.CoinsDB().Cursor());
2284 tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
2285 }
2286 bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins, node.rpc_interruption_point);
2287 result.pushKV("success", res);
2288 result.pushKV("txouts", count);
2289 result.pushKV("height", tip->nHeight);
2290 result.pushKV("bestblock", tip->GetBlockHash().GetHex());
2291
2292 for (const auto& it : coins) {
2293 const COutPoint& outpoint = it.first;
2294 const Coin& coin = it.second;
2295 const CTxOut& txo = coin.out;
2296 const CBlockIndex& coinb_block{*CHECK_NONFATAL(tip->GetAncestor(coin.nHeight))};
2297 input_txos.push_back(txo);
2298 total_in += txo.nValue;
2299
2300 UniValue unspent(UniValue::VOBJ);
2301 unspent.pushKV("txid", outpoint.hash.GetHex());
2302 unspent.pushKV("vout", outpoint.n);
2303 unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
2304 unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
2305 unspent.pushKV("amount", ValueFromAmount(txo.nValue));
2306 unspent.pushKV("coinbase", coin.IsCoinBase());
2307 unspent.pushKV("height", coin.nHeight);
2308 unspent.pushKV("blockhash", coinb_block.GetBlockHash().GetHex());
2309 unspent.pushKV("confirmations", tip->nHeight - coin.nHeight + 1);
2310
2311 unspents.push_back(std::move(unspent));
2312 }
2313 result.pushKV("unspents", std::move(unspents));
2314 result.pushKV("total_amount", ValueFromAmount(total_in));
2315 } else {
2316 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid action '%s'", action));
2317 }
2318 return result;
2319},
2320 };
2321}
2322
2324static std::atomic<int> g_scanfilter_progress;
2325static std::atomic<int> g_scanfilter_progress_height;
2326static std::atomic<bool> g_scanfilter_in_progress;
2327static std::atomic<bool> g_scanfilter_should_abort_scan;
2329{
2330private:
2331 bool m_could_reserve{false};
2332public:
2333 explicit BlockFiltersScanReserver() = default;
2334
2335 bool reserve() {
2337 if (g_scanfilter_in_progress.exchange(true)) {
2338 return false;
2339 }
2340 m_could_reserve = true;
2341 return true;
2342 }
2343
2345 if (m_could_reserve) {
2347 }
2348 }
2349};
2350
2351static bool CheckBlockFilterMatches(BlockManager& blockman, const CBlockIndex& blockindex, const GCSFilter::ElementSet& needles)
2352{
2353 const CBlock block{GetBlockChecked(blockman, blockindex)};
2354 const CBlockUndo block_undo{GetUndoChecked(blockman, blockindex)};
2355
2356 // Check if any of the outputs match the scriptPubKey
2357 for (const auto& tx : block.vtx) {
2358 if (std::any_of(tx->vout.cbegin(), tx->vout.cend(), [&](const auto& txout) {
2359 return needles.count(std::vector<unsigned char>(txout.scriptPubKey.begin(), txout.scriptPubKey.end())) != 0;
2360 })) {
2361 return true;
2362 }
2363 }
2364 // Check if any of the inputs match the scriptPubKey
2365 for (const auto& txundo : block_undo.vtxundo) {
2366 if (std::any_of(txundo.vprevout.cbegin(), txundo.vprevout.cend(), [&](const auto& coin) {
2367 return needles.count(std::vector<unsigned char>(coin.out.scriptPubKey.begin(), coin.out.scriptPubKey.end())) != 0;
2368 })) {
2369 return true;
2370 }
2371 }
2372
2373 return false;
2374}
2375
2377{
2378 return RPCHelpMan{"scanblocks",
2379 "\nReturn relevant blockhashes for given descriptors (requires blockfilterindex).\n"
2380 "This call may take several minutes. Make sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
2381 {
2384 RPCArg{"start_height", RPCArg::Type::NUM, RPCArg::Default{0}, "Height to start to scan from"},
2385 RPCArg{"stop_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"chain tip"}, "Height to stop to scan"},
2386 RPCArg{"filtertype", RPCArg::Type::STR, RPCArg::Default{BlockFilterTypeName(BlockFilterType::BASIC)}, "The type name of the filter"},
2388 {
2389 {"filter_false_positives", RPCArg::Type::BOOL, RPCArg::Default{false}, "Filter false positives (slower and may fail on pruned nodes). Otherwise they may occur at a rate of 1/M"},
2390 },
2391 RPCArgOptions{.oneline_description="options"}},
2392 },
2393 {
2395 RPCResult{"When action=='start'; only returns after scan completes", RPCResult::Type::OBJ, "", "", {
2396 {RPCResult::Type::NUM, "from_height", "The height we started the scan from"},
2397 {RPCResult::Type::NUM, "to_height", "The height we ended the scan at"},
2398 {RPCResult::Type::ARR, "relevant_blocks", "Blocks that may have matched a scanobject.", {
2399 {RPCResult::Type::STR_HEX, "blockhash", "A relevant blockhash"},
2400 }},
2401 {RPCResult::Type::BOOL, "completed", "true if the scan process was not aborted"}
2402 }},
2403 RPCResult{"when action=='status' and a scan is currently in progress", RPCResult::Type::OBJ, "", "", {
2404 {RPCResult::Type::NUM, "progress", "Approximate percent complete"},
2405 {RPCResult::Type::NUM, "current_height", "Height of the block currently being scanned"},
2406 },
2407 },
2409 },
2411 HelpExampleCli("scanblocks", "start '[\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"]' 300000") +
2412 HelpExampleCli("scanblocks", "start '[\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"]' 100 150 basic") +
2413 HelpExampleCli("scanblocks", "status") +
2414 HelpExampleRpc("scanblocks", "\"start\", [\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"], 300000") +
2415 HelpExampleRpc("scanblocks", "\"start\", [\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"], 100, 150, \"basic\"") +
2416 HelpExampleRpc("scanblocks", "\"status\"")
2417 },
2418 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2419{
2421 if (request.params[0].get_str() == "status") {
2422 BlockFiltersScanReserver reserver;
2423 if (reserver.reserve()) {
2424 // no scan in progress
2425 return NullUniValue;
2426 }
2427 ret.pushKV("progress", g_scanfilter_progress.load());
2428 ret.pushKV("current_height", g_scanfilter_progress_height.load());
2429 return ret;
2430 } else if (request.params[0].get_str() == "abort") {
2431 BlockFiltersScanReserver reserver;
2432 if (reserver.reserve()) {
2433 // reserve was possible which means no scan was running
2434 return false;
2435 }
2436 // set the abort flag
2438 return true;
2439 } else if (request.params[0].get_str() == "start") {
2440 BlockFiltersScanReserver reserver;
2441 if (!reserver.reserve()) {
2442 throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
2443 }
2444 const std::string filtertype_name{request.params[4].isNull() ? "basic" : request.params[4].get_str()};
2445
2446 BlockFilterType filtertype;
2447 if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2448 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown filtertype");
2449 }
2450
2451 UniValue options{request.params[5].isNull() ? UniValue::VOBJ : request.params[5]};
2452 bool filter_false_positives{options.exists("filter_false_positives") ? options["filter_false_positives"].get_bool() : false};
2453
2454 BlockFilterIndex* index = GetBlockFilterIndex(filtertype);
2455 if (!index) {
2456 throw JSONRPCError(RPC_MISC_ERROR, "Index is not enabled for filtertype " + filtertype_name);
2457 }
2458
2459 NodeContext& node = EnsureAnyNodeContext(request.context);
2461
2462 // set the start-height
2463 const CBlockIndex* start_index = nullptr;
2464 const CBlockIndex* stop_block = nullptr;
2465 {
2466 LOCK(cs_main);
2467 CChain& active_chain = chainman.ActiveChain();
2468 start_index = active_chain.Genesis();
2469 stop_block = active_chain.Tip(); // If no stop block is provided, stop at the chain tip.
2470 if (!request.params[2].isNull()) {
2471 start_index = active_chain[request.params[2].getInt<int>()];
2472 if (!start_index) {
2473 throw JSONRPCError(RPC_MISC_ERROR, "Invalid start_height");
2474 }
2475 }
2476 if (!request.params[3].isNull()) {
2477 stop_block = active_chain[request.params[3].getInt<int>()];
2478 if (!stop_block || stop_block->nHeight < start_index->nHeight) {
2479 throw JSONRPCError(RPC_MISC_ERROR, "Invalid stop_height");
2480 }
2481 }
2482 }
2483 CHECK_NONFATAL(start_index);
2484 CHECK_NONFATAL(stop_block);
2485
2486 // loop through the scan objects, add scripts to the needle_set
2487 GCSFilter::ElementSet needle_set;
2488 for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
2489 FlatSigningProvider provider;
2490 std::vector<CScript> scripts = EvalDescriptorStringOrObject(scanobject, provider);
2491 for (const CScript& script : scripts) {
2492 needle_set.emplace(script.begin(), script.end());
2493 }
2494 }
2495 UniValue blocks(UniValue::VARR);
2496 const int amount_per_chunk = 10000;
2497 std::vector<BlockFilter> filters;
2498 int start_block_height = start_index->nHeight; // for progress reporting
2499 const int total_blocks_to_process = stop_block->nHeight - start_block_height;
2500
2503 g_scanfilter_progress_height = start_block_height;
2504 bool completed = true;
2505
2506 const CBlockIndex* end_range = nullptr;
2507 do {
2508 node.rpc_interruption_point(); // allow a clean shutdown
2510 completed = false;
2511 break;
2512 }
2513
2514 // split the lookup range in chunks if we are deeper than 'amount_per_chunk' blocks from the stopping block
2515 int start_block = !end_range ? start_index->nHeight : start_index->nHeight + 1; // to not include the previous round 'end_range' block
2516 end_range = (start_block + amount_per_chunk < stop_block->nHeight) ?
2517 WITH_LOCK(::cs_main, return chainman.ActiveChain()[start_block + amount_per_chunk]) :
2518 stop_block;
2519
2520 if (index->LookupFilterRange(start_block, end_range, filters)) {
2521 for (const BlockFilter& filter : filters) {
2522 // compare the elements-set with each filter
2523 if (filter.GetFilter().MatchAny(needle_set)) {
2524 if (filter_false_positives) {
2525 // Double check the filter matches by scanning the block
2526 const CBlockIndex& blockindex = *CHECK_NONFATAL(WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(filter.GetBlockHash())));
2527
2528 if (!CheckBlockFilterMatches(chainman.m_blockman, blockindex, needle_set)) {
2529 continue;
2530 }
2531 }
2532
2533 blocks.push_back(filter.GetBlockHash().GetHex());
2534 }
2535 }
2536 }
2537 start_index = end_range;
2538
2539 // update progress
2540 int blocks_processed = end_range->nHeight - start_block_height;
2541 if (total_blocks_to_process > 0) { // avoid division by zero
2542 g_scanfilter_progress = (int)(100.0 / total_blocks_to_process * blocks_processed);
2543 } else {
2545 }
2547
2548 // Finish if we reached the stop block
2549 } while (start_index != stop_block);
2550
2551 ret.pushKV("from_height", start_block_height);
2552 ret.pushKV("to_height", start_index->nHeight); // start_index is always the last scanned block here
2553 ret.pushKV("relevant_blocks", std::move(blocks));
2554 ret.pushKV("completed", completed);
2555 }
2556 else {
2557 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid action '%s'", request.params[0].get_str()));
2558 }
2559 return ret;
2560},
2561 };
2562}
2563
2565{
2566 return RPCHelpMan{"getblockfilter",
2567 "\nRetrieve a BIP 157 content filter for a particular block.\n",
2568 {
2569 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hash of the block"},
2570 {"filtertype", RPCArg::Type::STR, RPCArg::Default{BlockFilterTypeName(BlockFilterType::BASIC)}, "The type name of the filter"},
2571 },
2572 RPCResult{
2573 RPCResult::Type::OBJ, "", "",
2574 {
2575 {RPCResult::Type::STR_HEX, "filter", "the hex-encoded filter data"},
2576 {RPCResult::Type::STR_HEX, "header", "the hex-encoded filter header"},
2577 }},
2579 HelpExampleCli("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" \"basic\"") +
2580 HelpExampleRpc("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\", \"basic\"")
2581 },
2582 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2583{
2584 uint256 block_hash = ParseHashV(request.params[0], "blockhash");
2585 std::string filtertype_name = BlockFilterTypeName(BlockFilterType::BASIC);
2586 if (!request.params[1].isNull()) {
2587 filtertype_name = request.params[1].get_str();
2588 }
2589
2590 BlockFilterType filtertype;
2591 if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2592 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown filtertype");
2593 }
2594
2595 BlockFilterIndex* index = GetBlockFilterIndex(filtertype);
2596 if (!index) {
2597 throw JSONRPCError(RPC_MISC_ERROR, "Index is not enabled for filtertype " + filtertype_name);
2598 }
2599
2600 const CBlockIndex* block_index;
2601 bool block_was_connected;
2602 {
2603 ChainstateManager& chainman = EnsureAnyChainman(request.context);
2604 LOCK(cs_main);
2605 block_index = chainman.m_blockman.LookupBlockIndex(block_hash);
2606 if (!block_index) {
2607 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
2608 }
2609 block_was_connected = block_index->IsValid(BLOCK_VALID_SCRIPTS);
2610 }
2611
2612 bool index_ready = index->BlockUntilSyncedToCurrentChain();
2613
2614 BlockFilter filter;
2615 uint256 filter_header;
2616 if (!index->LookupFilter(block_index, filter) ||
2617 !index->LookupFilterHeader(block_index, filter_header)) {
2618 int err_code;
2619 std::string errmsg = "Filter not found.";
2620
2621 if (!block_was_connected) {
2622 err_code = RPC_INVALID_ADDRESS_OR_KEY;
2623 errmsg += " Block was not connected to active chain.";
2624 } else if (!index_ready) {
2625 err_code = RPC_MISC_ERROR;
2626 errmsg += " Block filters are still in the process of being indexed.";
2627 } else {
2628 err_code = RPC_INTERNAL_ERROR;
2629 errmsg += " This error is unexpected and indicates index corruption.";
2630 }
2631
2632 throw JSONRPCError(err_code, errmsg);
2633 }
2634
2636 ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
2637 ret.pushKV("header", filter_header.GetHex());
2638 return ret;
2639},
2640 };
2641}
2642
2649{
2650 return RPCHelpMan{
2651 "dumptxoutset",
2652 "Write the serialized UTXO set to a file.",
2653 {
2654 {"path", RPCArg::Type::STR, RPCArg::Optional::NO, "Path to the output file. If relative, will be prefixed by datadir."},
2655 },
2656 RPCResult{
2657 RPCResult::Type::OBJ, "", "",
2658 {
2659 {RPCResult::Type::NUM, "coins_written", "the number of coins written in the snapshot"},
2660 {RPCResult::Type::STR_HEX, "base_hash", "the hash of the base of the snapshot"},
2661 {RPCResult::Type::NUM, "base_height", "the height of the base of the snapshot"},
2662 {RPCResult::Type::STR, "path", "the absolute path that the snapshot was written to"},
2663 {RPCResult::Type::STR_HEX, "txoutset_hash", "the hash of the UTXO set contents"},
2664 {RPCResult::Type::NUM, "nchaintx", "the number of transactions in the chain up to and including the base block"},
2665 }
2666 },
2668 HelpExampleCli("dumptxoutset", "utxo.dat")
2669 },
2670 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2671{
2672 const ArgsManager& args{EnsureAnyArgsman(request.context)};
2673 const fs::path path = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(request.params[0].get_str()));
2674 // Write to a temporary path and then move into `path` on completion
2675 // to avoid confusion due to an interruption.
2676 const fs::path temppath = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(request.params[0].get_str() + ".incomplete"));
2677
2678 if (fs::exists(path)) {
2679 throw JSONRPCError(
2681 path.utf8string() + " already exists. If you are sure this is what you want, "
2682 "move it out of the way first");
2683 }
2684
2685 FILE* file{fsbridge::fopen(temppath, "wb")};
2686 AutoFile afile{file};
2687 if (afile.IsNull()) {
2688 throw JSONRPCError(
2690 "Couldn't open file " + temppath.utf8string() + " for writing.");
2691 }
2692
2693 NodeContext& node = EnsureAnyNodeContext(request.context);
2695 node, node.chainman->ActiveChainstate(), afile, path, temppath);
2696 fs::rename(temppath, path);
2697
2698 result.pushKV("path", path.utf8string());
2699 return result;
2700},
2701 };
2702}
2703
2706 Chainstate& chainstate,
2707 AutoFile& afile,
2708 const fs::path& path,
2709 const fs::path& temppath)
2710{
2711 std::unique_ptr<CCoinsViewCursor> pcursor;
2712 std::optional<CCoinsStats> maybe_stats;
2713 const CBlockIndex* tip;
2714
2715 {
2716 // We need to lock cs_main to ensure that the coinsdb isn't written to
2717 // between (i) flushing coins cache to disk (coinsdb), (ii) getting stats
2718 // based upon the coinsdb, and (iii) constructing a cursor to the
2719 // coinsdb for use below this block.
2720 //
2721 // Cursors returned by leveldb iterate over snapshots, so the contents
2722 // of the pcursor will not be affected by simultaneous writes during
2723 // use below this block.
2724 //
2725 // See discussion here:
2726 // https://github.com/bitcoin/bitcoin/pull/15606#discussion_r274479369
2727 //
2728 LOCK(::cs_main);
2729
2730 chainstate.ForceFlushStateToDisk();
2731
2732 maybe_stats = GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman, CoinStatsHashType::HASH_SERIALIZED, node.rpc_interruption_point);
2733 if (!maybe_stats) {
2734 throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
2735 }
2736
2737 pcursor = chainstate.CoinsDB().Cursor();
2738 tip = CHECK_NONFATAL(chainstate.m_blockman.LookupBlockIndex(maybe_stats->hashBlock));
2739 }
2740
2741 LOG_TIME_SECONDS(strprintf("writing UTXO snapshot at height %s (%s) to file %s (via %s)",
2742 tip->nHeight, tip->GetBlockHash().ToString(),
2743 fs::PathToString(path), fs::PathToString(temppath)));
2744
2745 SnapshotMetadata metadata{chainstate.m_chainman.GetParams().MessageStart(), tip->GetBlockHash(), maybe_stats->coins_count};
2746
2747 afile << metadata;
2748
2749 COutPoint key;
2750 Txid last_hash;
2751 Coin coin;
2752 unsigned int iter{0};
2753 size_t written_coins_count{0};
2754 std::vector<std::pair<uint32_t, Coin>> coins;
2755
2756 // To reduce space the serialization format of the snapshot avoids
2757 // duplication of tx hashes. The code takes advantage of the guarantee by
2758 // leveldb that keys are lexicographically sorted.
2759 // In the coins vector we collect all coins that belong to a certain tx hash
2760 // (key.hash) and when we have them all (key.hash != last_hash) we write
2761 // them to file using the below lambda function.
2762 // See also https://github.com/bitcoin/bitcoin/issues/25675
2763 auto write_coins_to_file = [&](AutoFile& afile, const Txid& last_hash, const std::vector<std::pair<uint32_t, Coin>>& coins, size_t& written_coins_count) {
2764 afile << last_hash;
2765 WriteCompactSize(afile, coins.size());
2766 for (const auto& [n, coin] : coins) {
2767 WriteCompactSize(afile, n);
2768 afile << coin;
2769 ++written_coins_count;
2770 }
2771 };
2772
2773 pcursor->GetKey(key);
2774 last_hash = key.hash;
2775 while (pcursor->Valid()) {
2776 if (iter % 5000 == 0) node.rpc_interruption_point();
2777 ++iter;
2778 if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
2779 if (key.hash != last_hash) {
2780 write_coins_to_file(afile, last_hash, coins, written_coins_count);
2781 last_hash = key.hash;
2782 coins.clear();
2783 }
2784 coins.emplace_back(key.n, coin);
2785 }
2786 pcursor->Next();
2787 }
2788
2789 if (!coins.empty()) {
2790 write_coins_to_file(afile, last_hash, coins, written_coins_count);
2791 }
2792
2793 CHECK_NONFATAL(written_coins_count == maybe_stats->coins_count);
2794
2795 afile.fclose();
2796
2797 UniValue result(UniValue::VOBJ);
2798 result.pushKV("coins_written", written_coins_count);
2799 result.pushKV("base_hash", tip->GetBlockHash().ToString());
2800 result.pushKV("base_height", tip->nHeight);
2801 result.pushKV("path", path.utf8string());
2802 result.pushKV("txoutset_hash", maybe_stats->hashSerialized.ToString());
2803 result.pushKV("nchaintx", tip->m_chain_tx_count);
2804 return result;
2805}
2806
2808{
2809 return RPCHelpMan{
2810 "loadtxoutset",
2811 "Load the serialized UTXO set from a file.\n"
2812 "Once this snapshot is loaded, its contents will be "
2813 "deserialized into a second chainstate data structure, which is then used to sync to "
2814 "the network's tip. "
2815 "Meanwhile, the original chainstate will complete the initial block download process in "
2816 "the background, eventually validating up to the block that the snapshot is based upon.\n\n"
2817
2818 "The result is a usable bitcoind instance that is current with the network tip in a "
2819 "matter of minutes rather than hours. UTXO snapshot are typically obtained from "
2820 "third-party sources (HTTP, torrent, etc.) which is reasonable since their "
2821 "contents are always checked by hash.\n\n"
2822
2823 "You can find more information on this process in the `assumeutxo` design "
2824 "document (<https://github.com/bitcoin/bitcoin/blob/master/doc/design/assumeutxo.md>).",
2825 {
2826 {"path",
2829 "path to the snapshot file. If relative, will be prefixed by datadir."},
2830 },
2831 RPCResult{
2832 RPCResult::Type::OBJ, "", "",
2833 {
2834 {RPCResult::Type::NUM, "coins_loaded", "the number of coins loaded from the snapshot"},
2835 {RPCResult::Type::STR_HEX, "tip_hash", "the hash of the base of the snapshot"},
2836 {RPCResult::Type::NUM, "base_height", "the height of the base of the snapshot"},
2837 {RPCResult::Type::STR, "path", "the absolute path that the snapshot was loaded from"},
2838 }
2839 },
2841 HelpExampleCli("loadtxoutset", "utxo.dat")
2842 },
2843 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2844{
2845 NodeContext& node = EnsureAnyNodeContext(request.context);
2847 const fs::path path{AbsPathForConfigVal(EnsureArgsman(node), fs::u8path(self.Arg<std::string>("path")))};
2848
2849 FILE* file{fsbridge::fopen(path, "rb")};
2850 AutoFile afile{file};
2851 if (afile.IsNull()) {
2852 throw JSONRPCError(
2854 "Couldn't open file " + path.utf8string() + " for reading.");
2855 }
2856
2857 SnapshotMetadata metadata{chainman.GetParams().MessageStart()};
2858 try {
2859 afile >> metadata;
2860 } catch (const std::ios_base::failure& e) {
2861 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("Unable to parse metadata: %s", e.what()));
2862 }
2863
2864 auto activation_result{chainman.ActivateSnapshot(afile, metadata, false)};
2865 if (!activation_result) {
2866 throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to load UTXO snapshot: %s. (%s)", util::ErrorString(activation_result).original, path.utf8string()));
2867 }
2868
2869 // Because we can't provide historical blocks during tip or background sync.
2870 // Update local services to reflect we are a limited peer until we are fully sync.
2871 node.connman->RemoveLocalServices(NODE_NETWORK);
2872 // Setting the limited state is usually redundant because the node can always
2873 // provide the last 288 blocks, but it doesn't hurt to set it.
2874 node.connman->AddLocalServices(NODE_NETWORK_LIMITED);
2875
2876 CBlockIndex& snapshot_index{*CHECK_NONFATAL(*activation_result)};
2877
2878 UniValue result(UniValue::VOBJ);
2879 result.pushKV("coins_loaded", metadata.m_coins_count);
2880 result.pushKV("tip_hash", snapshot_index.GetBlockHash().ToString());
2881 result.pushKV("base_height", snapshot_index.nHeight);
2882 result.pushKV("path", fs::PathToString(path));
2883 return result;
2884},
2885 };
2886}
2887
2888const std::vector<RPCResult> RPCHelpForChainstate{
2889 {RPCResult::Type::NUM, "blocks", "number of blocks in this chainstate"},
2890 {RPCResult::Type::STR_HEX, "bestblockhash", "blockhash of the tip"},
2891 {RPCResult::Type::NUM, "difficulty", "difficulty of the tip"},
2892 {RPCResult::Type::NUM, "verificationprogress", "progress towards the network tip"},
2893 {RPCResult::Type::STR_HEX, "snapshot_blockhash", /*optional=*/true, "the base block of the snapshot this chainstate is based on, if any"},
2894 {RPCResult::Type::NUM, "coins_db_cache_bytes", "size of the coinsdb cache"},
2895 {RPCResult::Type::NUM, "coins_tip_cache_bytes", "size of the coinstip cache"},
2896 {RPCResult::Type::BOOL, "validated", "whether the chainstate is fully validated. True if all blocks in the chainstate were validated, false if the chain is based on a snapshot and the snapshot has not yet been validated."},
2897};
2898
2900{
2901return RPCHelpMan{
2902 "getchainstates",
2903 "\nReturn information about chainstates.\n",
2904 {},
2905 RPCResult{
2906 RPCResult::Type::OBJ, "", "", {
2907 {RPCResult::Type::NUM, "headers", "the number of headers seen so far"},
2908 {RPCResult::Type::ARR, "chainstates", "list of the chainstates ordered by work, with the most-work (active) chainstate last", {{RPCResult::Type::OBJ, "", "", RPCHelpForChainstate},}},
2909 }
2910 },
2912 HelpExampleCli("getchainstates", "")
2913 + HelpExampleRpc("getchainstates", "")
2914 },
2915 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2916{
2917 LOCK(cs_main);
2919
2920 ChainstateManager& chainman = EnsureAnyChainman(request.context);
2921
2922 auto make_chain_data = [&](const Chainstate& cs, bool validated) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
2925 if (!cs.m_chain.Tip()) {
2926 return data;
2927 }
2928 const CChain& chain = cs.m_chain;
2929 const CBlockIndex* tip = chain.Tip();
2930
2931 data.pushKV("blocks", (int)chain.Height());
2932 data.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
2933 data.pushKV("difficulty", GetDifficulty(*tip));
2934 data.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
2935 data.pushKV("coins_db_cache_bytes", cs.m_coinsdb_cache_size_bytes);
2936 data.pushKV("coins_tip_cache_bytes", cs.m_coinstip_cache_size_bytes);
2937 if (cs.m_from_snapshot_blockhash) {
2938 data.pushKV("snapshot_blockhash", cs.m_from_snapshot_blockhash->ToString());
2939 }
2940 data.pushKV("validated", validated);
2941 return data;
2942 };
2943
2944 obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
2945
2946 const auto& chainstates = chainman.GetAll();
2947 UniValue obj_chainstates{UniValue::VARR};
2948 for (Chainstate* cs : chainstates) {
2949 obj_chainstates.push_back(make_chain_data(*cs, !cs->m_from_snapshot_blockhash || chainstates.size() == 1));
2950 }
2951 obj.pushKV("chainstates", std::move(obj_chainstates));
2952 return obj;
2953}
2954 };
2955}
2956
2957
2959{
2960 static const CRPCCommand commands[]{
2961 {"blockchain", &getblockchaininfo},
2962 {"blockchain", &getchaintxstats},
2963 {"blockchain", &getblockstats},
2964 {"blockchain", &getbestblockhash},
2965 {"blockchain", &getblockcount},
2966 {"blockchain", &getblock},
2967 {"blockchain", &getblockfrompeer},
2968 {"blockchain", &getblockhash},
2969 {"blockchain", &getblockheader},
2970 {"blockchain", &getchaintips},
2971 {"blockchain", &getdifficulty},
2972 {"blockchain", &getdeploymentinfo},
2973 {"blockchain", &gettxout},
2974 {"blockchain", &gettxoutsetinfo},
2975 {"blockchain", &pruneblockchain},
2976 {"blockchain", &verifychain},
2977 {"blockchain", &preciousblock},
2978 {"blockchain", &scantxoutset},
2979 {"blockchain", &scanblocks},
2980 {"blockchain", &getblockfilter},
2981 {"blockchain", &dumptxoutset},
2982 {"blockchain", &loadtxoutset},
2983 {"blockchain", &getchainstates},
2984 {"hidden", &invalidateblock},
2985 {"hidden", &reconsiderblock},
2986 {"hidden", &waitfornewblock},
2987 {"hidden", &waitforblock},
2988 {"hidden", &waitforblockheight},
2990 };
2991 for (const auto& c : commands) {
2992 t.appendCommand(c.name, &c);
2993 }
2994}
static constexpr CAmount MAX_MONEY
No amount larger than this (in satoshi) is valid.
Definition amount.h:26
bool MoneyRange(const CAmount &nValue)
Definition amount.h:27
int64_t CAmount
Amount in satoshis (Can be negative)
Definition amount.h:12
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 config.cpp:214
int ret
ArgsManager & args
Definition bitcoind.cpp:270
static RPCHelpMan getblock()
static RPCHelpMan getdifficulty()
static const auto scan_result_abort
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 int ComputeNextBlockAndDepth(const CBlockIndex &tip, const CBlockIndex &blockindex, const CBlockIndex *&next)
const RPCResult getblock_vin
static RPCHelpMan syncwithvalidationinterfacequeue()
static CBlockUndo GetUndoChecked(BlockManager &blockman, const CBlockIndex &blockindex)
static RPCHelpMan getchaintips()
static RPCHelpMan loadtxoutset()
static RPCHelpMan gettxoutsetinfo()
static RPCHelpMan getchainstates()
static std::atomic< int > g_scanfilter_progress_height
static RPCHelpMan getblockstats()
static std::atomic< bool > g_scanfilter_should_abort_scan
static std::atomic< int > g_scanfilter_progress
RAII object to prevent concurrency issue when scanning blockfilters.
static void SoftForkDescPushBack(const CBlockIndex *blockindex, UniValue &softforks, const ChainstateManager &chainman, Consensus::BuriedDeployment dep)
static RPCHelpMan preciousblock()
static constexpr size_t PER_UTXO_OVERHEAD
double GetDifficulty(const CBlockIndex &blockindex)
Get the difficulty of the net wrt to the given block index.
static const auto scan_objects_arg_desc
static RPCHelpMan scantxoutset()
CoinStatsHashType ParseHashType(const std::string &hash_type_input)
static bool CheckBlockFilterMatches(BlockManager &blockman, const CBlockIndex &blockindex, const GCSFilter::ElementSet &needles)
static std::condition_variable cond_blockchange
static std::atomic< int > g_scan_progress
RAII object to prevent concurrency issue when scanning the txout set.
static CBlock GetBlockChecked(BlockManager &blockman, const CBlockIndex &blockindex)
std::optional< int > GetPruneHeight(const BlockManager &blockman, const CChain &chain)
Return height of highest block that has been pruned, or std::nullopt if no blocks have been pruned.
RPCHelpMan getdeploymentinfo()
static RPCHelpMan getblockfilter()
static RPCHelpMan getbestblockhash()
RPCHelpMan getblockchaininfo()
static RPCHelpMan getchaintxstats()
static RPCHelpMan waitforblock()
static RPCHelpMan getblockfrompeer()
static const auto scan_result_status_some
static RPCHelpMan getblockhash()
void RegisterBlockchainRPCCommands(CRPCTable &t)
void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector< std::pair< CAmount, int64_t > > &scores, int64_t total_weight)
Used by getblockstats to get feerates at different percentiles by weight
static std::optional< kernel::CCoinsStats > GetUTXOStats(CCoinsView *view, node::BlockManager &blockman, kernel::CoinStatsHashType hash_type, const std::function< void()> &interruption_point={}, const CBlockIndex *pindex=nullptr, bool index_requested=true)
Calculate statistics about the unspent transaction output set.
static RPCHelpMan gettxout()
static RPCHelpMan verifychain()
static std::atomic< bool > g_should_abort_scan
const std::vector< RPCResult > RPCHelpForChainstate
UniValue blockheaderToJSON(const CBlockIndex &tip, const CBlockIndex &blockindex)
Block header to JSON.
static const auto scan_action_arg_desc
static RPCHelpMan waitforblockheight()
static const CBlockIndex * ParseHashOrHeight(const UniValue &param, ChainstateManager &chainman)
UniValue blockToJSON(BlockManager &blockman, const CBlock &block, const CBlockIndex &tip, const CBlockIndex &blockindex, TxVerbosity verbosity)
Block description to JSON.
static RPCHelpMan pruneblockchain()
static RPCHelpMan getblockheader()
static RPCHelpMan scanblocks()
static std::atomic< bool > g_scanfilter_in_progress
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
static RPCHelpMan dumptxoutset()
Serialize the UTXO set to a file for loading elsewhere.
static std::vector< uint8_t > GetRawBlockChecked(BlockManager &blockman, const CBlockIndex &blockindex)
static RPCHelpMan getblockcount()
static RPCHelpMan waitfornewblock()
static const auto scan_result_status_none
void RPCNotifyBlockChange(const CBlockIndex *pindex)
Callback for when block tip changed.
static constexpr int NUM_GETBLOCKSTATS_PERCENTILES
Definition blockchain.h:28
const std::string & BlockFilterTypeName(BlockFilterType filter_type)
Get the human-readable name for a filter type.
bool BlockFilterTypeByName(const std::string &name, BlockFilterType &filter_type)
Find a filter type by its human-readable name.
BlockFilterType
Definition blockfilter.h:93
BlockFilterIndex * GetBlockFilterIndex(BlockFilterType filter_type)
Get a block filter index by type.
@ BLOCK_VALID_SCRIPTS
Scripts & signatures ok.
Definition chain.h:115
@ BLOCK_VALID_TREE
All parent headers found, difficulty matches, timestamp >= median previous, checkpoint.
Definition chain.h:97
@ BLOCK_HAVE_DATA
full block available in blk*.dat
Definition chain.h:121
@ BLOCK_FAILED_MASK
Definition chain.h:127
@ BLOCK_HAVE_MASK
Definition chain.h:123
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:37
const CChainParams & Params()
Return the currently selected parameters.
#define LIST_CHAIN_NAMES
List of possible chain / network names
#define CHECK_NONFATAL(condition)
Identity function.
Definition check.h:73
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Definition args.h:232
Non-refcounted RAII wrapper for FILE*.
Definition streams.h:389
int fclose()
Definition streams.h:406
Complete block filter struct as defined in BIP 157.
const std::vector< unsigned char > & GetEncodedFilter() const LIFETIMEBOUND
BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of bloc...
bool LookupFilterRange(int start_height, const CBlockIndex *stop_index, std::vector< BlockFilter > &filters_out) const
Get a range of filters between two heights on a chain.
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.
BlockFiltersScanReserver()=default
Definition block.h:69
std::vector< CTransactionRef > vtx
Definition block.h:72
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition chain.h:141
uint256 hashMerkleRoot
Definition chain.h:188
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition chain.h:147
uint64_t m_chain_tx_count
(memory only) Number of transactions in the chain up to and including this block.
Definition chain.h:176
CBlockHeader GetBlockHeader() const
Definition chain.h:230
arith_uint256 nChainWork
(memory only) Total amount of work (expected number of hashes) in the chain up to and including this ...
Definition chain.h:165
uint32_t nTime
Definition chain.h:189
uint32_t nNonce
Definition chain.h:191
uint256 GetBlockHash() const
Definition chain.h:243
int64_t GetBlockTime() const
Definition chain.h:266
int64_t GetMedianTimePast() const
Definition chain.h:278
uint32_t nBits
Definition chain.h:190
unsigned int nTx
Number of transactions in this block.
Definition chain.h:170
bool IsValid(enum BlockStatus nUpTo=BLOCK_VALID_TRANSACTIONS) const EXCLUSIVE_LOCKS_REQUIRED(
Check whether this block index entry is valid up to the passed validity level.
Definition chain.h:295
int32_t nVersion
block header
Definition chain.h:187
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition chain.cpp:120
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition chain.h:153
FlatFilePos GetBlockPos() const EXCLUSIVE_LOCKS_REQUIRED(
Definition chain.h:208
Undo information for a CBlock.
Definition undo.h:63
std::vector< CTxUndo > vtxundo
Definition undo.h:65
An in-memory indexed chain of blocks.
Definition chain.h:417
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition chain.h:433
CBlockIndex * Genesis() const
Returns the index entry for the genesis block of this chain, or nullptr if none.
Definition chain.h:427
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:71
int Height() const
Return the maximal height in the chain.
Definition chain.h:462
const CBlockIndex * FindFork(const CBlockIndex *pindex) const
Find the last common block between this chain and a block index entry.
Definition chain.cpp:60
bool Contains(const CBlockIndex *pindex) const
Efficiently check whether a block is present in this chain.
Definition chain.h:447
std::string GetChainTypeString() const
Return the chain type string.
const MessageStartChars & MessageStart() const
Definition chainparams.h:94
const ChainTxData & TxData() const
const Consensus::Params & GetConsensus() const
Definition chainparams.h:93
uint64_t PruneAfterHeight() const
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition coins.h:360
uint256 GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
Definition coins.cpp:175
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition coins.cpp:61
Cursor for iterating over CoinsView state.
Definition coins.h:229
virtual void Next()=0
virtual bool Valid() const =0
virtual bool GetKey(COutPoint &key) const =0
virtual bool GetValue(Coin &coin) const =0
std::unique_ptr< CCoinsViewCursor > Cursor() const override
Get a cursor to iterate over the whole state.
Definition txdb.cpp:180
Abstract view on the open txout dataset.
Definition coins.h:304
virtual uint256 GetBestBlock() const
Retrieve the block hash whose state this CCoinsView currently represents.
Definition coins.cpp:13
CCoinsView that brings transactions from a mempool into view.
Definition txmempool.h:835
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
GetCoin, returning whether it exists and is not spent.
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition transaction.h:29
uint32_t n
Definition transaction.h:32
RPC command dispatcher.
Definition server.h:133
Serialized script, used inside transaction inputs and outputs.
Definition script.h:414
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition txmempool.h:304
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition txmempool.h:390
bool isSpent(const COutPoint &outpoint) const
An output of a transaction.
CScript scriptPubKey
CAmount nValue
Undo information for a CTransaction.
Definition undo.h:53
RAII wrapper for VerifyDB: Verify consistency of the block and coin databases.
Definition validation.h:422
VerifyDBResult VerifyDB(Chainstate &chainstate, const Consensus::Params &consensus_params, 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:513
CChain m_chain
The current chain of blockheaders we consult and build on.
Definition validation.h:593
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition validation.h:619
void ForceFlushStateToDisk()
Unconditionally flush all changes to disk.
CCoinsViewDB & CoinsDB() EXCLUSIVE_LOCKS_REQUIRED(
Definition validation.h:627
ChainstateManager & m_chainman
The chainstate manager that owns this chainstate.
Definition validation.h:553
node::BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all Chainstate instances.
Definition validation.h:548
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition validation.h:871
node::BlockMap & BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(
SnapshotCompletionResult MaybeCompleteSnapshotValidation() EXCLUSIVE_LOCKS_REQUIRED(const CBlockIndex *GetSnapshotBaseBlock() const EXCLUSIVE_LOCKS_REQUIRED(Chainstate ActiveChainstate)() const
Once the background validation chainstate has reached the height which is the base of the UTXO snapsh...
kernel::Notifications & GetNotifications() const
Definition validation.h:986
bool IsInitialBlockDownload() const
Check whether we are doing an initial block download (synchronizing from disk or network)
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
VersionBitsCache m_versionbitscache
Track versionbit status.
const CChainParams & GetParams() const
Definition validation.h:981
const Consensus::Params & GetConsensus() const
Definition validation.h:982
util::Result< CBlockIndex * > ActivateSnapshot(AutoFile &coins_file, const node::SnapshotMetadata &metadata, bool in_memory)
Construct and activate a Chainstate on the basis of UTXO snapshot data.
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Chainstate &InitializeChainstate(CTxMemPool *mempool) EXCLUSIVE_LOCKS_REQUIRED(std::vector< Chainstate * GetAll)()
Instantiate a new chainstate.
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
A UTXO entry.
Definition coins.h:33
bool IsCoinBase() const
Definition coins.h:57
CTxOut out
unspent transaction output
Definition coins.h:36
uint32_t nHeight
at which height this containing transaction was included in the active block chain
Definition coins.h:42
unsigned int fCoinBase
whether containing transaction was a coinbase
Definition coins.h:39
CoinsViewScanReserver()=default
Double ended buffer combining vector and stream-like interfaces.
Definition streams.h:147
std::unordered_set< Element, ByteVectorHash > ElementSet
Definition blockfilter.h:32
Different type to mark Mutex at global scope.
Definition sync.h:140
virtual std::optional< std::string > FetchBlock(NodeId peer_id, const CBlockIndex &block_index)=0
Attempt to manually fetch block from a given peer.
auto Arg(std::string_view key) const
Helper to get a required or default-valued request argument.
Definition util.h:430
void push_back(UniValue val)
Definition univalue.cpp:104
const std::string & get_str() const
bool isNull() const
Definition univalue.h:79
size_t size() const
Definition univalue.h:71
const std::vector< UniValue > & getValues() const
Int getInt() const
Definition univalue.h:138
const UniValue & get_array() const
bool isNum() const
Definition univalue.h:84
void pushKV(std::string key, UniValue val)
Definition univalue.cpp:126
bool IsValid() const
Definition validation.h:122
std::string ToString() const
Definition validation.h:128
int StateSinceHeight(const CBlockIndex *pindexPrev, const Consensus::Params &params, Consensus::DeploymentPos pos) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get the block height at which the BIP9 deployment switched into the state for the block after pindexP...
static BIP9Stats Statistics(const CBlockIndex *pindex, const Consensus::Params &params, Consensus::DeploymentPos pos, std::vector< bool > *signalling_blocks=nullptr)
Get the numerical statistics for a given deployment for the signalling period that includes pindex.
ThresholdState State(const CBlockIndex *pindexPrev, const Consensus::Params &params, Consensus::DeploymentPos pos) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get the BIP9 state for a given deployment for the block after pindexPrev.
std::string GetHex() const
Definition uint256.cpp:11
std::string ToString() const
Definition uint256.cpp:47
std::string GetHex() const
Hex encoding of the number (with the most significant digits first).
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition fs.h:33
std::string utf8string() const
Return a UTF-8 representation of the path as a std::string, for compatibility with code using std::st...
Definition fs.h:63
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos) const
Functions for disk access for blocks.
static constexpr auto PRUNE_TARGET_MANUAL
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
bool ReadRawBlockFromDisk(std::vector< uint8_t > &block, const FlatFilePos &pos) const
bool UndoReadFromDisk(CBlockUndo &blockundo, const CBlockIndex &index) const
uint64_t GetPruneTarget() const
Attempt to stay below this number of bytes of block files.
uint64_t CalculateCurrentUsage()
Calculate the amount of disk space the block & undo files currently use.
bool IsPruneMode() const
Whether running in -prune mode.
Metadata describing a serialized version of a UTXO set from which an assumeutxo Chainstate can be con...
constexpr const std::byte * begin() const
static transaction_identifier FromUint256(const uint256 &id)
256-bit opaque blob.
Definition uint256.h:178
std::unique_ptr< CoinStatsIndex > g_coin_stats_index
The global UTXO set hash object.
static int64_t GetBlockWeight(const CBlock &block)
Definition validation.h:153
static int32_t GetTransactionWeight(const CTransaction &tx)
Definition validation.h:149
static const unsigned int MAX_BLOCK_SERIALIZED_SIZE
The maximum allowed size for a serialized block, in bytes (only for buffer size limits)
Definition consensus.h:13
static const int WITNESS_SCALE_FACTOR
Definition consensus.h:21
void TxToUniv(const CTransaction &tx, const uint256 &block_hash, UniValue &entry, bool include_hex=true, const CTxUndo *txundo=nullptr, TxVerbosity verbosity=TxVerbosity::SHOW_DETAILS)
TxVerbosity
Verbose level for block's transaction.
Definition core_io.h:27
@ SHOW_DETAILS_AND_PREVOUT
The same as previous option with information about prevouts if available.
@ SHOW_TXID
Only TXID for each block's transaction.
@ SHOW_DETAILS
Include TXID, inputs, outputs, and other common block's transaction information.
void ScriptToUniv(const CScript &script, UniValue &out, bool include_hex=true, bool include_address=false, const SigningProvider *provider=nullptr)
UniValue ValueFromAmount(const CAmount amount)
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition cs_main.cpp:8
std::string DeploymentName(Consensus::BuriedDeployment dep)
bool DeploymentActiveAfter(const CBlockIndex *pindexPrev, const Consensus::Params &params, Consensus::BuriedDeployment dep, VersionBitsCache &versionbitscache)
Determine if a deployment is active for the next block.
bool DeploymentEnabled(const Consensus::Params &params, Consensus::BuriedDeployment dep)
Determine if a deployment is enabled (can ever be active)
const std::string CURRENCY_UNIT
Definition feerate.h:17
#define T(expected, seed, data)
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition hex_base.cpp:29
#define LogPrint(category,...)
Definition logging.h:293
unsigned int nHeight
static void pool cs
@ RPC
Definition logging.h:49
DeploymentPos
Definition params.h:32
@ DEPLOYMENT_TAPROOT
Definition params.h:34
@ DEPLOYMENT_TESTDUMMY
Definition params.h:33
BuriedDeployment
A buried deployment is one where the height of the activation has been hardcoded into the client impl...
Definition params.h:22
@ DEPLOYMENT_DERSIG
Definition params.h:26
@ DEPLOYMENT_CSV
Definition params.h:27
@ DEPLOYMENT_SEGWIT
Definition params.h:28
@ DEPLOYMENT_HEIGHTINCB
Definition params.h:24
@ DEPLOYMENT_CLTV
Definition params.h:25
static path u8path(const std::string &utf8_str)
Definition fs.h:75
static bool exists(const path &p)
Definition fs.h:89
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition fs.h:151
FILE * fopen(const fs::path &p, const char *mode)
Definition fs.cpp:26
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition fs.cpp:36
static bool ComputeUTXOStats(CCoinsView *view, CCoinsStats &stats, T hash_obj, const std::function< void()> &interruption_point)
Calculate statistics about the unspent transaction output set.
CoinStatsHashType
Definition coinstats.h:26
UniValue GetWarningsForRpc(const Warnings &warnings, bool use_deprecated)
RPC helper function that wraps warnings.GetMessages().
Definition warnings.cpp:54
bilingual_str ErrorString(const Result< T > &result)
Definition result.h:93
std::string MakeUnorderedList(const std::vector< std::string > &items)
Create an unordered multi-line list of items.
Definition string.h:136
int64_t NodeId
Definition net.h:97
static constexpr TransactionSerParams TX_NO_WITNESS
static constexpr TransactionSerParams TX_WITH_WITNESS
std::shared_ptr< const CTransaction > CTransactionRef
@ NODE_NETWORK_LIMITED
Definition protocol.h:327
@ NODE_NETWORK
Definition protocol.h:315
UniValue JSONRPCError(int code, const std::string &message)
Definition request.cpp:70
@ RPC_MISC_ERROR
General application defined errors.
Definition protocol.h:40
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition protocol.h:44
@ RPC_INTERNAL_ERROR
Definition protocol.h:36
@ RPC_DATABASE_ERROR
Database error.
Definition protocol.h:45
@ RPC_DESERIALIZATION_ERROR
Error parsing or validating structure in raw format.
Definition protocol.h:46
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition protocol.h:42
std::vector< CScript > EvalDescriptorStringOrObject(const UniValue &scanobject, FlatSigningProvider &provider, const bool expand_priv)
Evaluate a descriptor given as a string, or as a {"desc":...,"range":...} object, with default range ...
Definition util.cpp:1329
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition util.cpp:168
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition util.cpp:186
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:43
std::string GetAllOutputTypes()
Gets all existing output types formatted for RPC help sections.
Definition util.cpp:46
uint256 ParseHashV(const UniValue &v, std::string_view name)
Utilities: convert hex-encoded Values (throws error if not hex).
Definition util.cpp:102
std::unique_ptr< Descriptor > InferDescriptor(const CScript &script, const SigningProvider &provider)
Find a descriptor for the specified script, using information from provider where possible.
size_t GetSerializeSize(const T &t)
Definition serialize.h:1101
void WriteCompactSize(SizeComputer &os, uint64_t nSize)
Definition serialize.h:1095
bool IsDeprecatedRPCEnabled(const std::string &method)
Definition server.cpp:358
bool IsRPCRunning()
Query whether RPC is running.
Definition server.cpp:327
ChainstateManager & EnsureAnyChainman(const std::any &context)
NodeContext & EnsureAnyNodeContext(const std::any &context)
CTxMemPool & EnsureMemPool(const NodeContext &node)
PeerManager & EnsurePeerman(const NodeContext &node)
ChainstateManager & EnsureChainman(const NodeContext &node)
ArgsManager & EnsureArgsman(const NodeContext &node)
ArgsManager & EnsureAnyArgsman(const std::any &context)
unsigned char * UCharCast(char *c)
Definition span.h:288
Display status of an in-progress BIP9 softfork.
Definition versionbits.h:41
int count
Number of blocks with the version bit set since the beginning of the current period.
Definition versionbits.h:49
int elapsed
Number of blocks elapsed since the beginning of the current period.
Definition versionbits.h:47
int threshold
Number of blocks with the version bit set required to activate the softfork.
Definition versionbits.h:45
bool possible
False if there are not enough blocks left in this period to pass activation threshold.
Definition versionbits.h:51
int period
Length of blocks of the BIP9 signalling period.
Definition versionbits.h:43
Comparison function for sorting the getchaintips heads.
bool operator()(const CBlockIndex *a, const CBlockIndex *b) const
int min_activation_height
If lock in occurs, delay activation until at least this block height.
Definition params.h:54
int bit
Bit position to select the particular bit in nVersion.
Definition params.h:45
int64_t nTimeout
Timeout/expiry MedianTime for the deployment attempt.
Definition params.h:49
int64_t nStartTime
Start MedianTime for version bits miner confirmation.
Definition params.h:47
BIP9Deployment vDeployments[MAX_VERSION_BITS_DEPLOYMENTS]
Definition params.h:107
int DeploymentHeight(BuriedDeployment dep) const
Definition params.h:136
int64_t nPowTargetSpacing
Definition params.h:117
Definition util.h:172
@ RANGE
Special type that is a NUM or [NUM,NUM].
@ STR_HEX
Special type that is a STR with only hex chars.
@ OBJ_NAMED_PARAMS
Special type that behaves almost exactly like OBJ, defining an options object with a list of pre-defi...
std::string DefaultHint
Hint for default value.
Definition util.h:206
@ OMITTED
Optional argument for which the default value is omitted from help text for one of two reasons:
@ NO
Required arg.
@ ELISION
Special type to denote elision (...)
@ NUM_TIME
Special numeric to denote unix epoch time.
@ ARR_FIXED
Special array that has a fixed number of entries.
@ OBJ_DYN
Special dictionary with keys that are not literals.
@ STR_HEX
Special string with only hex chars.
@ STR_AMOUNT
Special string to represent a floating point amount.
std::optional< CAmount > total_amount
The total amount, or nullopt if an overflow occurred calculating it.
Definition coinstats.h:41
CAmount total_unspendable_amount
Total cumulative amount of unspendable coins up to and including this block.
Definition coinstats.h:54
CAmount total_unspendables_scripts
Total cumulative amount of outputs sent to unspendable scripts (OP_RETURN for example) up to and incl...
Definition coinstats.h:66
CAmount total_new_outputs_ex_coinbase_amount
Total cumulative amount of outputs created up to and including this block.
Definition coinstats.h:58
uint64_t nTransactions
Definition coinstats.h:35
uint64_t nTransactionOutputs
Definition coinstats.h:36
CAmount total_coinbase_amount
Total cumulative amount of coinbase outputs up to and including this block.
Definition coinstats.h:60
bool index_used
Signals if the coinstatsindex was used to retrieve the statistics.
Definition coinstats.h:47
CAmount total_unspendables_bip30
The two unspendable coinbase outputs total amount caused by BIP30.
Definition coinstats.h:64
CAmount total_unspendables_genesis_block
The unspendable coinbase amount from the genesis block.
Definition coinstats.h:62
CAmount total_prevout_spent_amount
Total cumulative amount of prevouts spent up to and including this block.
Definition coinstats.h:56
uint256 hashSerialized
Definition coinstats.h:38
CAmount total_unspendables_unclaimed_rewards
Total cumulative amount of coins lost due to unclaimed miner rewards up to and including this block.
Definition coinstats.h:68
NodeContext struct containing references to chain state and connection state.
Definition context.h:55
#define WAIT_LOCK(cs, name)
Definition sync.h:262
#define AssertLockNotHeld(cs)
Definition sync.h:147
#define LOCK(cs)
Definition sync.h:257
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition sync.h:301
#define AssertLockHeld(cs)
Definition sync.h:142
static int count
#define EXCLUSIVE_LOCKS_REQUIRED(...)
#define GUARDED_BY(x)
#define LOG_TIME_SECONDS(end_msg)
Definition timer.h:107
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
bilingual_str _(ConstevalStringLiteral str)
Translation function.
Definition translation.h:80
static const uint32_t MEMPOOL_HEIGHT
Fake height value used in Coin to signify they are only in the memory pool (since 0....
Definition txmempool.h:49
const UniValue NullUniValue
Definition univalue.cpp:16
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...
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams)
const std::vector< std::string > CHECKLEVEL_DOC
Documentation for argument 'checklevel'.
void PruneBlockFilesManual(Chainstate &active_chainstate, int nManualPruneHeight)
Prune block files up to a given height.
bool IsBIP30Repeat(const CBlockIndex &block_index)
Identifies blocks that overwrote an existing coinbase output in the UTXO set (see BIP30)
static constexpr int DEFAULT_CHECKLEVEL
Definition validation.h:70
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:68
static const signed int DEFAULT_CHECKBLOCKS
Definition validation.h:69
ThresholdState
BIP 9 defines a finite-state-machine to deploy a softfork in multiple stages.
Definition versionbits.h:27