Bitcoin Core 29.99.0
P2P Digital Currency
blockchain.cpp
Go to the documentation of this file.
1// Copyright (c) 2010 Satoshi Nakamoto
2// Copyright (c) 2009-present 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 <interfaces/mining.h>
26#include <kernel/coinstats.h>
27#include <logging/timer.h>
28#include <net.h>
29#include <net_processing.h>
30#include <node/blockstorage.h>
31#include <node/context.h>
32#include <node/transaction.h>
33#include <node/utxo_snapshot.h>
34#include <node/warnings.h>
36#include <rpc/server.h>
37#include <rpc/server_util.h>
38#include <rpc/util.h>
39#include <script/descriptor.h>
40#include <serialize.h>
41#include <streams.h>
42#include <sync.h>
43#include <txdb.h>
44#include <txmempool.h>
45#include <undo.h>
46#include <univalue.h>
47#include <util/check.h>
48#include <util/fs.h>
49#include <util/strencodings.h>
50#include <util/translation.h>
51#include <validation.h>
52#include <validationinterface.h>
53#include <versionbits.h>
54
55#include <cstdint>
56
57#include <condition_variable>
58#include <iterator>
59#include <memory>
60#include <mutex>
61#include <optional>
62#include <vector>
63
66
73
74std::tuple<std::unique_ptr<CCoinsViewCursor>, CCoinsStats, const CBlockIndex*>
76 Chainstate& chainstate,
77 const std::function<void()>& interruption_point = {})
79
81 Chainstate& chainstate,
82 CCoinsViewCursor* pcursor,
83 CCoinsStats* maybe_stats,
84 const CBlockIndex* tip,
85 AutoFile& afile,
86 const fs::path& path,
87 const fs::path& temppath,
88 const std::function<void()>& interruption_point = {});
89
90/* Calculate the difficulty for a given block index.
91 */
92double GetDifficulty(const CBlockIndex& blockindex)
93{
94 int nShift = (blockindex.nBits >> 24) & 0xff;
95 double dDiff =
96 (double)0x0000ffff / (double)(blockindex.nBits & 0x00ffffff);
97
98 while (nShift < 29)
99 {
100 dDiff *= 256.0;
101 nShift++;
102 }
103 while (nShift > 29)
104 {
105 dDiff /= 256.0;
106 nShift--;
107 }
108
109 return dDiff;
110}
111
112static int ComputeNextBlockAndDepth(const CBlockIndex& tip, const CBlockIndex& blockindex, const CBlockIndex*& next)
113{
114 next = tip.GetAncestor(blockindex.nHeight + 1);
115 if (next && next->pprev == &blockindex) {
116 return tip.nHeight - blockindex.nHeight + 1;
117 }
118 next = nullptr;
119 return &blockindex == &tip ? 1 : -1;
120}
121
122static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateManager& chainman)
123{
125 CChain& active_chain = chainman.ActiveChain();
126
127 if (param.isNum()) {
128 const int height{param.getInt<int>()};
129 if (height < 0) {
130 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d is negative", height));
131 }
132 const int current_tip{active_chain.Height()};
133 if (height > current_tip) {
134 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Target block height %d after current tip %d", height, current_tip));
135 }
136
137 return active_chain[height];
138 } else {
139 const uint256 hash{ParseHashV(param, "hash_or_height")};
140 const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
141
142 if (!pindex) {
143 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
144 }
145
146 return pindex;
147 }
148}
149
150UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex, const uint256 pow_limit)
151{
152 // Serialize passed information without accessing chain state of the active chain!
153 AssertLockNotHeld(cs_main); // For performance reasons
154
155 UniValue result(UniValue::VOBJ);
156 result.pushKV("hash", blockindex.GetBlockHash().GetHex());
157 const CBlockIndex* pnext;
158 int confirmations = ComputeNextBlockAndDepth(tip, blockindex, pnext);
159 result.pushKV("confirmations", confirmations);
160 result.pushKV("height", blockindex.nHeight);
161 result.pushKV("version", blockindex.nVersion);
162 result.pushKV("versionHex", strprintf("%08x", blockindex.nVersion));
163 result.pushKV("merkleroot", blockindex.hashMerkleRoot.GetHex());
164 result.pushKV("time", blockindex.nTime);
165 result.pushKV("mediantime", blockindex.GetMedianTimePast());
166 result.pushKV("nonce", blockindex.nNonce);
167 result.pushKV("bits", strprintf("%08x", blockindex.nBits));
168 result.pushKV("target", GetTarget(tip, pow_limit).GetHex());
169 result.pushKV("difficulty", GetDifficulty(blockindex));
170 result.pushKV("chainwork", blockindex.nChainWork.GetHex());
171 result.pushKV("nTx", blockindex.nTx);
172
173 if (blockindex.pprev)
174 result.pushKV("previousblockhash", blockindex.pprev->GetBlockHash().GetHex());
175 if (pnext)
176 result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex());
177 return result;
178}
179
180UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity, const uint256 pow_limit)
181{
182 UniValue result = blockheaderToJSON(tip, blockindex, pow_limit);
183
184 result.pushKV("strippedsize", (int)::GetSerializeSize(TX_NO_WITNESS(block)));
185 result.pushKV("size", (int)::GetSerializeSize(TX_WITH_WITNESS(block)));
186 result.pushKV("weight", (int)::GetBlockWeight(block));
188
189 switch (verbosity) {
191 for (const CTransactionRef& tx : block.vtx) {
192 txs.push_back(tx->GetHash().GetHex());
193 }
194 break;
195
198 CBlockUndo blockUndo;
199 const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))};
200 bool have_undo{is_not_pruned && WITH_LOCK(::cs_main, return blockindex.nStatus & BLOCK_HAVE_UNDO)};
201 if (have_undo && !blockman.ReadBlockUndo(blockUndo, blockindex)) {
202 throw JSONRPCError(RPC_INTERNAL_ERROR, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event.");
203 }
204 for (size_t i = 0; i < block.vtx.size(); ++i) {
205 const CTransactionRef& tx = block.vtx.at(i);
206 // coinbase transaction (i.e. i == 0) doesn't have undo data
207 const CTxUndo* txundo = (have_undo && i > 0) ? &blockUndo.vtxundo.at(i - 1) : nullptr;
209 TxToUniv(*tx, /*block_hash=*/uint256(), /*entry=*/objTx, /*include_hex=*/true, txundo, verbosity);
210 txs.push_back(std::move(objTx));
211 }
212 break;
213 }
214
215 result.pushKV("tx", std::move(txs));
216
217 return result;
218}
219
221{
222 return RPCHelpMan{
223 "getblockcount",
224 "Returns the height of the most-work fully-validated chain.\n"
225 "The genesis block has height 0.\n",
226 {},
227 RPCResult{
228 RPCResult::Type::NUM, "", "The current block count"},
230 HelpExampleCli("getblockcount", "")
231 + HelpExampleRpc("getblockcount", "")
232 },
233 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
234{
235 ChainstateManager& chainman = EnsureAnyChainman(request.context);
236 LOCK(cs_main);
237 return chainman.ActiveChain().Height();
238},
239 };
240}
241
243{
244 return RPCHelpMan{
245 "getbestblockhash",
246 "Returns the hash of the best (tip) block in the most-work fully-validated chain.\n",
247 {},
248 RPCResult{
249 RPCResult::Type::STR_HEX, "", "the block hash, hex-encoded"},
251 HelpExampleCli("getbestblockhash", "")
252 + HelpExampleRpc("getbestblockhash", "")
253 },
254 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
255{
256 ChainstateManager& chainman = EnsureAnyChainman(request.context);
257 LOCK(cs_main);
258 return chainman.ActiveChain().Tip()->GetBlockHash().GetHex();
259},
260 };
261}
262
264{
265 return RPCHelpMan{
266 "waitfornewblock",
267 "Waits for any new block and returns useful info about it.\n"
268 "\nReturns the current block on timeout or exit.\n"
269 "\nMake sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
270 {
271 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
272 },
273 RPCResult{
274 RPCResult::Type::OBJ, "", "",
275 {
276 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
277 {RPCResult::Type::NUM, "height", "Block height"},
278 }},
280 HelpExampleCli("waitfornewblock", "1000")
281 + HelpExampleRpc("waitfornewblock", "1000")
282 },
283 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
284{
285 int timeout = 0;
286 if (!request.params[0].isNull())
287 timeout = request.params[0].getInt<int>();
288 if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout");
289
290 NodeContext& node = EnsureAnyNodeContext(request.context);
291 Mining& miner = EnsureMining(node);
292
293 // Abort if RPC came out of warmup too early
294 BlockRef current_block{CHECK_NONFATAL(miner.getTip()).value()};
295 std::optional<BlockRef> block = timeout ? miner.waitTipChanged(current_block.hash, std::chrono::milliseconds(timeout)) :
296 miner.waitTipChanged(current_block.hash);
297
298 // Return current block upon shutdown
299 if (block) current_block = *block;
300
302 ret.pushKV("hash", current_block.hash.GetHex());
303 ret.pushKV("height", current_block.height);
304 return ret;
305},
306 };
307}
308
310{
311 return RPCHelpMan{
312 "waitforblock",
313 "Waits for a specific new block and returns useful info about it.\n"
314 "\nReturns the current block on timeout or exit.\n"
315 "\nMake sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
316 {
317 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "Block hash to wait for."},
318 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
319 },
320 RPCResult{
321 RPCResult::Type::OBJ, "", "",
322 {
323 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
324 {RPCResult::Type::NUM, "height", "Block height"},
325 }},
327 HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\" 1000")
328 + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
329 },
330 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
331{
332 int timeout = 0;
333
334 uint256 hash(ParseHashV(request.params[0], "blockhash"));
335
336 if (!request.params[1].isNull())
337 timeout = request.params[1].getInt<int>();
338 if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout");
339
340 NodeContext& node = EnsureAnyNodeContext(request.context);
341 Mining& miner = EnsureMining(node);
342
343 // Abort if RPC came out of warmup too early
344 BlockRef current_block{CHECK_NONFATAL(miner.getTip()).value()};
345
346 const auto deadline{std::chrono::steady_clock::now() + 1ms * timeout};
347 while (current_block.hash != hash) {
348 std::optional<BlockRef> block;
349 if (timeout) {
350 auto now{std::chrono::steady_clock::now()};
351 if (now >= deadline) break;
352 const MillisecondsDouble remaining{deadline - now};
353 block = miner.waitTipChanged(current_block.hash, remaining);
354 } else {
355 block = miner.waitTipChanged(current_block.hash);
356 }
357 // Return current block upon shutdown
358 if (!block) break;
359 current_block = *block;
360 }
361
363 ret.pushKV("hash", current_block.hash.GetHex());
364 ret.pushKV("height", current_block.height);
365 return ret;
366},
367 };
368}
369
371{
372 return RPCHelpMan{
373 "waitforblockheight",
374 "Waits for (at least) block height and returns the height and hash\n"
375 "of the current tip.\n"
376 "\nReturns the current block on timeout or exit.\n"
377 "\nMake sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
378 {
379 {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "Block height to wait for."},
380 {"timeout", RPCArg::Type::NUM, RPCArg::Default{0}, "Time in milliseconds to wait for a response. 0 indicates no timeout."},
381 },
382 RPCResult{
383 RPCResult::Type::OBJ, "", "",
384 {
385 {RPCResult::Type::STR_HEX, "hash", "The blockhash"},
386 {RPCResult::Type::NUM, "height", "Block height"},
387 }},
389 HelpExampleCli("waitforblockheight", "100 1000")
390 + HelpExampleRpc("waitforblockheight", "100, 1000")
391 },
392 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
393{
394 int timeout = 0;
395
396 int height = request.params[0].getInt<int>();
397
398 if (!request.params[1].isNull())
399 timeout = request.params[1].getInt<int>();
400 if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout");
401
402 NodeContext& node = EnsureAnyNodeContext(request.context);
403 Mining& miner = EnsureMining(node);
404
405 // Abort if RPC came out of warmup too early
406 BlockRef current_block{CHECK_NONFATAL(miner.getTip()).value()};
407
408 const auto deadline{std::chrono::steady_clock::now() + 1ms * timeout};
409
410 while (current_block.height < height) {
411 std::optional<BlockRef> block;
412 if (timeout) {
413 auto now{std::chrono::steady_clock::now()};
414 if (now >= deadline) break;
415 const MillisecondsDouble remaining{deadline - now};
416 block = miner.waitTipChanged(current_block.hash, remaining);
417 } else {
418 block = miner.waitTipChanged(current_block.hash);
419 }
420 // Return current block on shutdown
421 if (!block) break;
422 current_block = *block;
423 }
424
426 ret.pushKV("hash", current_block.hash.GetHex());
427 ret.pushKV("height", current_block.height);
428 return ret;
429},
430 };
431}
432
434{
435 return RPCHelpMan{
436 "syncwithvalidationinterfacequeue",
437 "Waits for the validation interface queue to catch up on everything that was there when we entered this function.\n",
438 {},
441 HelpExampleCli("syncwithvalidationinterfacequeue","")
442 + HelpExampleRpc("syncwithvalidationinterfacequeue","")
443 },
444 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
445{
446 NodeContext& node = EnsureAnyNodeContext(request.context);
447 CHECK_NONFATAL(node.validation_signals)->SyncWithValidationInterfaceQueue();
448 return UniValue::VNULL;
449},
450 };
451}
452
454{
455 return RPCHelpMan{
456 "getdifficulty",
457 "Returns the proof-of-work difficulty as a multiple of the minimum difficulty.\n",
458 {},
459 RPCResult{
460 RPCResult::Type::NUM, "", "the proof-of-work difficulty as a multiple of the minimum difficulty."},
462 HelpExampleCli("getdifficulty", "")
463 + HelpExampleRpc("getdifficulty", "")
464 },
465 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
466{
467 ChainstateManager& chainman = EnsureAnyChainman(request.context);
468 LOCK(cs_main);
469 return GetDifficulty(*CHECK_NONFATAL(chainman.ActiveChain().Tip()));
470},
471 };
472}
473
475{
476 return RPCHelpMan{
477 "getblockfrompeer",
478 "Attempt to fetch block from a given peer.\n\n"
479 "We must have the header for this block, e.g. using submitheader.\n"
480 "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"
481 "Subsequent calls for the same block may cause the response from the previous peer to be ignored.\n"
482 "Peers generally ignore requests for a stale block that they never fully verified, or one that is more than a month old.\n"
483 "When a peer does not respond with a block, we will disconnect.\n"
484 "Note: The block could be re-pruned as soon as it is received.\n\n"
485 "Returns an empty JSON object if the request was successfully scheduled.",
486 {
487 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash to try to fetch"},
488 {"peer_id", RPCArg::Type::NUM, RPCArg::Optional::NO, "The peer to fetch it from (see getpeerinfo for peer IDs)"},
489 },
490 RPCResult{RPCResult::Type::OBJ, "", /*optional=*/false, "", {}},
492 HelpExampleCli("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0")
493 + HelpExampleRpc("getblockfrompeer", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 0")
494 },
495 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
496{
497 const NodeContext& node = EnsureAnyNodeContext(request.context);
499 PeerManager& peerman = EnsurePeerman(node);
500
501 const uint256& block_hash{ParseHashV(request.params[0], "blockhash")};
502 const NodeId peer_id{request.params[1].getInt<int64_t>()};
503
504 const CBlockIndex* const index = WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(block_hash););
505
506 if (!index) {
507 throw JSONRPCError(RPC_MISC_ERROR, "Block header missing");
508 }
509
510 // Fetching blocks before the node has syncing past their height can prevent block files from
511 // being pruned, so we avoid it if the node is in prune mode.
512 if (chainman.m_blockman.IsPruneMode() && index->nHeight > WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip()->nHeight)) {
513 throw JSONRPCError(RPC_MISC_ERROR, "In prune mode, only blocks that the node has already synced previously can be fetched from a peer");
514 }
515
516 const bool block_has_data = WITH_LOCK(::cs_main, return index->nStatus & BLOCK_HAVE_DATA);
517 if (block_has_data) {
518 throw JSONRPCError(RPC_MISC_ERROR, "Block already downloaded");
519 }
520
521 if (const auto err{peerman.FetchBlock(peer_id, *index)}) {
522 throw JSONRPCError(RPC_MISC_ERROR, err.value());
523 }
524 return UniValue::VOBJ;
525},
526 };
527}
528
530{
531 return RPCHelpMan{
532 "getblockhash",
533 "Returns hash of block in best-block-chain at height provided.\n",
534 {
535 {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The height index"},
536 },
537 RPCResult{
538 RPCResult::Type::STR_HEX, "", "The block hash"},
540 HelpExampleCli("getblockhash", "1000")
541 + HelpExampleRpc("getblockhash", "1000")
542 },
543 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
544{
545 ChainstateManager& chainman = EnsureAnyChainman(request.context);
546 LOCK(cs_main);
547 const CChain& active_chain = chainman.ActiveChain();
548
549 int nHeight = request.params[0].getInt<int>();
550 if (nHeight < 0 || nHeight > active_chain.Height())
551 throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
552
553 const CBlockIndex* pblockindex = active_chain[nHeight];
554 return pblockindex->GetBlockHash().GetHex();
555},
556 };
557}
558
560{
561 return RPCHelpMan{
562 "getblockheader",
563 "If verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"
564 "If verbose is true, returns an Object with information about blockheader <hash>.\n",
565 {
566 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
567 {"verbose", RPCArg::Type::BOOL, RPCArg::Default{true}, "true for a json object, false for the hex-encoded data"},
568 },
569 {
570 RPCResult{"for verbose = true",
571 RPCResult::Type::OBJ, "", "",
572 {
573 {RPCResult::Type::STR_HEX, "hash", "the block hash (same as provided)"},
574 {RPCResult::Type::NUM, "confirmations", "The number of confirmations, or -1 if the block is not on the main chain"},
575 {RPCResult::Type::NUM, "height", "The block height or index"},
576 {RPCResult::Type::NUM, "version", "The block version"},
577 {RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},
578 {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
579 {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
580 {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
581 {RPCResult::Type::NUM, "nonce", "The nonce"},
582 {RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},
583 {RPCResult::Type::STR_HEX, "target", "The difficulty target"},
584 {RPCResult::Type::NUM, "difficulty", "The difficulty"},
585 {RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the current chain"},
586 {RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
587 {RPCResult::Type::STR_HEX, "previousblockhash", /*optional=*/true, "The hash of the previous block (if available)"},
588 {RPCResult::Type::STR_HEX, "nextblockhash", /*optional=*/true, "The hash of the next block (if available)"},
589 }},
590 RPCResult{"for verbose=false",
591 RPCResult::Type::STR_HEX, "", "A string that is serialized, hex-encoded data for block 'hash'"},
592 },
594 HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
595 + HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
596 },
597 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
598{
599 uint256 hash(ParseHashV(request.params[0], "hash"));
600
601 bool fVerbose = true;
602 if (!request.params[1].isNull())
603 fVerbose = request.params[1].get_bool();
604
605 const CBlockIndex* pblockindex;
606 const CBlockIndex* tip;
607 ChainstateManager& chainman = EnsureAnyChainman(request.context);
608 {
609 LOCK(cs_main);
610 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
611 tip = chainman.ActiveChain().Tip();
612 }
613
614 if (!pblockindex) {
615 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
616 }
617
618 if (!fVerbose)
619 {
620 DataStream ssBlock{};
621 ssBlock << pblockindex->GetBlockHeader();
622 std::string strHex = HexStr(ssBlock);
623 return strHex;
624 }
625
626 return blockheaderToJSON(*tip, *pblockindex, chainman.GetConsensus().powLimit);
627},
628 };
629}
630
631void CheckBlockDataAvailability(BlockManager& blockman, const CBlockIndex& blockindex, bool check_for_undo)
632{
634 uint32_t flag = check_for_undo ? BLOCK_HAVE_UNDO : BLOCK_HAVE_DATA;
635 if (!(blockindex.nStatus & flag)) {
636 if (blockman.IsBlockPruned(blockindex)) {
637 throw JSONRPCError(RPC_MISC_ERROR, strprintf("%s not available (pruned data)", check_for_undo ? "Undo data" : "Block"));
638 }
639 if (check_for_undo) {
640 throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available");
641 }
642 throw JSONRPCError(RPC_MISC_ERROR, "Block not available (not fully downloaded)");
643 }
644}
645
646static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex& blockindex)
647{
648 CBlock block;
649 {
650 LOCK(cs_main);
651 CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/false);
652 }
653
654 if (!blockman.ReadBlock(block, blockindex)) {
655 // Block not found on disk. This shouldn't normally happen unless the block was
656 // pruned right after we released the lock above.
657 throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
658 }
659
660 return block;
661}
662
663static std::vector<std::byte> GetRawBlockChecked(BlockManager& blockman, const CBlockIndex& blockindex)
664{
665 std::vector<std::byte> data{};
666 FlatFilePos pos{};
667 {
668 LOCK(cs_main);
669 CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/false);
670 pos = blockindex.GetBlockPos();
671 }
672
673 if (!blockman.ReadRawBlock(data, pos)) {
674 // Block not found on disk. This shouldn't normally happen unless the block was
675 // pruned right after we released the lock above.
676 throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
677 }
678
679 return data;
680}
681
682static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex& blockindex)
683{
684 CBlockUndo blockUndo;
685
686 // The Genesis block does not have undo data
687 if (blockindex.nHeight == 0) return blockUndo;
688
689 {
690 LOCK(cs_main);
691 CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/true);
692 }
693
694 if (!blockman.ReadBlockUndo(blockUndo, blockindex)) {
695 throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
696 }
697
698 return blockUndo;
699}
700
702 RPCResult::Type::ARR, "vin", "",
703 {
704 {RPCResult::Type::OBJ, "", "",
705 {
706 {RPCResult::Type::ELISION, "", "The same output as verbosity = 2"},
707 {RPCResult::Type::OBJ, "prevout", "(Only if undo information is available)",
708 {
709 {RPCResult::Type::BOOL, "generated", "Coinbase or not"},
710 {RPCResult::Type::NUM, "height", "The height of the prevout"},
711 {RPCResult::Type::STR_AMOUNT, "value", "The value in " + CURRENCY_UNIT},
712 {RPCResult::Type::OBJ, "scriptPubKey", "",
713 {
714 {RPCResult::Type::STR, "asm", "Disassembly of the output script"},
715 {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
716 {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"},
717 {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
718 {RPCResult::Type::STR, "type", "The type (one of: " + GetAllOutputTypes() + ")"},
719 }},
720 }},
721 }},
722 }
723};
724
726{
727 return RPCHelpMan{
728 "getblock",
729 "If verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
730 "If verbosity is 1, returns an Object with information about block <hash>.\n"
731 "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction.\n"
732 "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",
733 {
734 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
735 {"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",
737 },
738 {
739 RPCResult{"for verbosity = 0",
740 RPCResult::Type::STR_HEX, "", "A string that is serialized, hex-encoded data for block 'hash'"},
741 RPCResult{"for verbosity = 1",
742 RPCResult::Type::OBJ, "", "",
743 {
744 {RPCResult::Type::STR_HEX, "hash", "the block hash (same as provided)"},
745 {RPCResult::Type::NUM, "confirmations", "The number of confirmations, or -1 if the block is not on the main chain"},
746 {RPCResult::Type::NUM, "size", "The block size"},
747 {RPCResult::Type::NUM, "strippedsize", "The block size excluding witness data"},
748 {RPCResult::Type::NUM, "weight", "The block weight as defined in BIP 141"},
749 {RPCResult::Type::NUM, "height", "The block height or index"},
750 {RPCResult::Type::NUM, "version", "The block version"},
751 {RPCResult::Type::STR_HEX, "versionHex", "The block version formatted in hexadecimal"},
752 {RPCResult::Type::STR_HEX, "merkleroot", "The merkle root"},
753 {RPCResult::Type::ARR, "tx", "The transaction ids",
754 {{RPCResult::Type::STR_HEX, "", "The transaction id"}}},
755 {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
756 {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
757 {RPCResult::Type::NUM, "nonce", "The nonce"},
758 {RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},
759 {RPCResult::Type::STR_HEX, "target", "The difficulty target"},
760 {RPCResult::Type::NUM, "difficulty", "The difficulty"},
761 {RPCResult::Type::STR_HEX, "chainwork", "Expected number of hashes required to produce the chain up to this block (in hex)"},
762 {RPCResult::Type::NUM, "nTx", "The number of transactions in the block"},
763 {RPCResult::Type::STR_HEX, "previousblockhash", /*optional=*/true, "The hash of the previous block (if available)"},
764 {RPCResult::Type::STR_HEX, "nextblockhash", /*optional=*/true, "The hash of the next block (if available)"},
765 }},
766 RPCResult{"for verbosity = 2",
767 RPCResult::Type::OBJ, "", "",
768 {
769 {RPCResult::Type::ELISION, "", "Same output as verbosity = 1"},
770 {RPCResult::Type::ARR, "tx", "",
771 {
772 {RPCResult::Type::OBJ, "", "",
773 {
774 {RPCResult::Type::ELISION, "", "The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 \"tx\" result"},
775 {RPCResult::Type::NUM, "fee", "The transaction fee in " + CURRENCY_UNIT + ", omitted if block undo data is not available"},
776 }},
777 }},
778 }},
779 RPCResult{"for verbosity = 3",
780 RPCResult::Type::OBJ, "", "",
781 {
782 {RPCResult::Type::ELISION, "", "Same output as verbosity = 2"},
783 {RPCResult::Type::ARR, "tx", "",
784 {
785 {RPCResult::Type::OBJ, "", "",
786 {
788 }},
789 }},
790 }},
791 },
793 HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
794 + HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
795 },
796 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
797{
798 uint256 hash(ParseHashV(request.params[0], "blockhash"));
799
800 int verbosity{ParseVerbosity(request.params[1], /*default_verbosity=*/1, /*allow_bool=*/true)};
801
802 const CBlockIndex* pblockindex;
803 const CBlockIndex* tip;
804 ChainstateManager& chainman = EnsureAnyChainman(request.context);
805 {
806 LOCK(cs_main);
807 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
808 tip = chainman.ActiveChain().Tip();
809
810 if (!pblockindex) {
811 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
812 }
813 }
814
815 const std::vector<std::byte> block_data{GetRawBlockChecked(chainman.m_blockman, *pblockindex)};
816
817 if (verbosity <= 0) {
818 return HexStr(block_data);
819 }
820
821 DataStream block_stream{block_data};
822 CBlock block{};
823 block_stream >> TX_WITH_WITNESS(block);
824
825 TxVerbosity tx_verbosity;
826 if (verbosity == 1) {
827 tx_verbosity = TxVerbosity::SHOW_TXID;
828 } else if (verbosity == 2) {
829 tx_verbosity = TxVerbosity::SHOW_DETAILS;
830 } else {
832 }
833
834 return blockToJSON(chainman.m_blockman, block, *tip, *pblockindex, tx_verbosity, chainman.GetConsensus().powLimit);
835},
836 };
837}
838
840std::optional<int> GetPruneHeight(const BlockManager& blockman, const CChain& chain) {
842
843 // Search for the last block missing block data or undo data. Don't let the
844 // search consider the genesis block, because the genesis block does not
845 // have undo data, but should not be considered pruned.
846 const CBlockIndex* first_block{chain[1]};
847 const CBlockIndex* chain_tip{chain.Tip()};
848
849 // If there are no blocks after the genesis block, or no blocks at all, nothing is pruned.
850 if (!first_block || !chain_tip) return std::nullopt;
851
852 // If the chain tip is pruned, everything is pruned.
853 if (!((chain_tip->nStatus & BLOCK_HAVE_MASK) == BLOCK_HAVE_MASK)) return chain_tip->nHeight;
854
855 const auto& first_unpruned{*CHECK_NONFATAL(blockman.GetFirstBlock(*chain_tip, /*status_mask=*/BLOCK_HAVE_MASK, first_block))};
856 if (&first_unpruned == first_block) {
857 // All blocks between first_block and chain_tip have data, so nothing is pruned.
858 return std::nullopt;
859 }
860
861 // Block before the first unpruned block is the last pruned block.
862 return CHECK_NONFATAL(first_unpruned.pprev)->nHeight;
863}
864
866{
867 return RPCHelpMan{"pruneblockchain",
868 "Attempts to delete block and undo data up to a specified height or timestamp, if eligible for pruning.\n"
869 "Requires `-prune` to be enabled at startup. While pruned data may be re-fetched in some cases (e.g., via `getblockfrompeer`), local deletion is irreversible.\n",
870 {
871 {"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"
872 " to prune blocks whose block time is at least 2 hours older than the provided timestamp."},
873 },
874 RPCResult{
875 RPCResult::Type::NUM, "", "Height of the last block pruned"},
877 HelpExampleCli("pruneblockchain", "1000")
878 + HelpExampleRpc("pruneblockchain", "1000")
879 },
880 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
881{
882 ChainstateManager& chainman = EnsureAnyChainman(request.context);
883 if (!chainman.m_blockman.IsPruneMode()) {
884 throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
885 }
886
887 LOCK(cs_main);
888 Chainstate& active_chainstate = chainman.ActiveChainstate();
889 CChain& active_chain = active_chainstate.m_chain;
890
891 int heightParam = request.params[0].getInt<int>();
892 if (heightParam < 0) {
893 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative block height.");
894 }
895
896 // Height value more than a billion is too high to be a block height, and
897 // too low to be a block time (corresponds to timestamp from Sep 2001).
898 if (heightParam > 1000000000) {
899 // Add a 2 hour buffer to include blocks which might have had old timestamps
900 const CBlockIndex* pindex = active_chain.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0);
901 if (!pindex) {
902 throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp.");
903 }
904 heightParam = pindex->nHeight;
905 }
906
907 unsigned int height = (unsigned int) heightParam;
908 unsigned int chainHeight = (unsigned int) active_chain.Height();
909 if (chainHeight < chainman.GetParams().PruneAfterHeight()) {
910 throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning.");
911 } else if (height > chainHeight) {
912 throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height.");
913 } else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
914 LogDebug(BCLog::RPC, "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks.\n");
915 height = chainHeight - MIN_BLOCKS_TO_KEEP;
916 }
917
918 PruneBlockFilesManual(active_chainstate, height);
919 return GetPruneHeight(chainman.m_blockman, active_chain).value_or(-1);
920},
921 };
922}
923
924CoinStatsHashType ParseHashType(const std::string& hash_type_input)
925{
926 if (hash_type_input == "hash_serialized_3") {
927 return CoinStatsHashType::HASH_SERIALIZED;
928 } else if (hash_type_input == "muhash") {
929 return CoinStatsHashType::MUHASH;
930 } else if (hash_type_input == "none") {
932 } else {
933 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("'%s' is not a valid hash_type", hash_type_input));
934 }
935}
936
942static std::optional<kernel::CCoinsStats> GetUTXOStats(CCoinsView* view, node::BlockManager& blockman,
944 const std::function<void()>& interruption_point = {},
945 const CBlockIndex* pindex = nullptr,
946 bool index_requested = true)
947{
948 // Use CoinStatsIndex if it is requested and available and a hash_type of Muhash or None was requested
949 if ((hash_type == kernel::CoinStatsHashType::MUHASH || hash_type == kernel::CoinStatsHashType::NONE) && g_coin_stats_index && index_requested) {
950 if (pindex) {
951 return g_coin_stats_index->LookUpStats(*pindex);
952 } else {
953 CBlockIndex& block_index = *CHECK_NONFATAL(WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(view->GetBestBlock())));
954 return g_coin_stats_index->LookUpStats(block_index);
955 }
956 }
957
958 // If the coinstats index isn't requested or is otherwise not usable, the
959 // pindex should either be null or equal to the view's best block. This is
960 // because without the coinstats index we can only get coinstats about the
961 // best block.
962 CHECK_NONFATAL(!pindex || pindex->GetBlockHash() == view->GetBestBlock());
963
964 return kernel::ComputeUTXOStats(hash_type, view, blockman, interruption_point);
965}
966
968{
969 return RPCHelpMan{
970 "gettxoutsetinfo",
971 "Returns statistics about the unspent transaction output set.\n"
972 "Note this call may take some time if you are not using coinstatsindex.\n",
973 {
974 {"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'."},
975 {"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).",
977 .skip_type_check = true,
978 .type_str = {"", "string or numeric"},
979 }},
980 {"use_index", RPCArg::Type::BOOL, RPCArg::Default{true}, "Use coinstatsindex, if available."},
981 },
982 RPCResult{
983 RPCResult::Type::OBJ, "", "",
984 {
985 {RPCResult::Type::NUM, "height", "The block height (index) of the returned statistics"},
986 {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at which these statistics are calculated"},
987 {RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs"},
988 {RPCResult::Type::NUM, "bogosize", "Database-independent, meaningless metric indicating the UTXO set size"},
989 {RPCResult::Type::STR_HEX, "hash_serialized_3", /*optional=*/true, "The serialized hash (only present if 'hash_serialized_3' hash_type is chosen)"},
990 {RPCResult::Type::STR_HEX, "muhash", /*optional=*/true, "The serialized hash (only present if 'muhash' hash_type is chosen)"},
991 {RPCResult::Type::NUM, "transactions", /*optional=*/true, "The number of transactions with unspent outputs (not available when coinstatsindex is used)"},
992 {RPCResult::Type::NUM, "disk_size", /*optional=*/true, "The estimated size of the chainstate on disk (not available when coinstatsindex is used)"},
993 {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of coins in the UTXO set"},
994 {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)"},
995 {RPCResult::Type::OBJ, "block_info", /*optional=*/true, "Info on amounts in the block at this block height (only available if coinstatsindex is used)",
996 {
997 {RPCResult::Type::STR_AMOUNT, "prevout_spent", "Total amount of all prevouts spent in this block"},
998 {RPCResult::Type::STR_AMOUNT, "coinbase", "Coinbase subsidy amount of this block"},
999 {RPCResult::Type::STR_AMOUNT, "new_outputs_ex_coinbase", "Total amount of new outputs created by this block"},
1000 {RPCResult::Type::STR_AMOUNT, "unspendable", "Total amount of unspendable outputs created in this block"},
1001 {RPCResult::Type::OBJ, "unspendables", "Detailed view of the unspendable categories",
1002 {
1003 {RPCResult::Type::STR_AMOUNT, "genesis_block", "The unspendable amount of the Genesis block subsidy"},
1004 {RPCResult::Type::STR_AMOUNT, "bip30", "Transactions overridden by duplicates (no longer possible with BIP30)"},
1005 {RPCResult::Type::STR_AMOUNT, "scripts", "Amounts sent to scripts that are unspendable (for example OP_RETURN outputs)"},
1006 {RPCResult::Type::STR_AMOUNT, "unclaimed_rewards", "Fee rewards that miners did not claim in their coinbase transaction"},
1007 }}
1008 }},
1009 }},
1011 HelpExampleCli("gettxoutsetinfo", "") +
1012 HelpExampleCli("gettxoutsetinfo", R"("none")") +
1013 HelpExampleCli("gettxoutsetinfo", R"("none" 1000)") +
1014 HelpExampleCli("gettxoutsetinfo", R"("none" '"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"')") +
1015 HelpExampleCli("-named gettxoutsetinfo", R"(hash_type='muhash' use_index='false')") +
1016 HelpExampleRpc("gettxoutsetinfo", "") +
1017 HelpExampleRpc("gettxoutsetinfo", R"("none")") +
1018 HelpExampleRpc("gettxoutsetinfo", R"("none", 1000)") +
1019 HelpExampleRpc("gettxoutsetinfo", R"("none", "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09")")
1020 },
1021 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1022{
1024
1025 const CBlockIndex* pindex{nullptr};
1026 const CoinStatsHashType hash_type{request.params[0].isNull() ? CoinStatsHashType::HASH_SERIALIZED : ParseHashType(request.params[0].get_str())};
1027 bool index_requested = request.params[2].isNull() || request.params[2].get_bool();
1028
1029 NodeContext& node = EnsureAnyNodeContext(request.context);
1031 Chainstate& active_chainstate = chainman.ActiveChainstate();
1032 active_chainstate.ForceFlushStateToDisk();
1033
1034 CCoinsView* coins_view;
1035 BlockManager* blockman;
1036 {
1037 LOCK(::cs_main);
1038 coins_view = &active_chainstate.CoinsDB();
1039 blockman = &active_chainstate.m_blockman;
1040 pindex = blockman->LookupBlockIndex(coins_view->GetBestBlock());
1041 }
1042
1043 if (!request.params[1].isNull()) {
1044 if (!g_coin_stats_index) {
1045 throw JSONRPCError(RPC_INVALID_PARAMETER, "Querying specific block heights requires coinstatsindex");
1046 }
1047
1048 if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1049 throw JSONRPCError(RPC_INVALID_PARAMETER, "hash_serialized_3 hash type cannot be queried for a specific block");
1050 }
1051
1052 if (!index_requested) {
1053 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot set use_index to false when querying for a specific block");
1054 }
1055 pindex = ParseHashOrHeight(request.params[1], chainman);
1056 }
1057
1058 if (index_requested && g_coin_stats_index) {
1059 if (!g_coin_stats_index->BlockUntilSyncedToCurrentChain()) {
1060 const IndexSummary summary{g_coin_stats_index->GetSummary()};
1061
1062 // If a specific block was requested and the index has already synced past that height, we can return the
1063 // data already even though the index is not fully synced yet.
1064 if (pindex->nHeight > summary.best_block_height) {
1065 throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to get data because coinstatsindex is still syncing. Current height: %d", summary.best_block_height));
1066 }
1067 }
1068 }
1069
1070 const std::optional<CCoinsStats> maybe_stats = GetUTXOStats(coins_view, *blockman, hash_type, node.rpc_interruption_point, pindex, index_requested);
1071 if (maybe_stats.has_value()) {
1072 const CCoinsStats& stats = maybe_stats.value();
1073 ret.pushKV("height", (int64_t)stats.nHeight);
1074 ret.pushKV("bestblock", stats.hashBlock.GetHex());
1075 ret.pushKV("txouts", (int64_t)stats.nTransactionOutputs);
1076 ret.pushKV("bogosize", (int64_t)stats.nBogoSize);
1077 if (hash_type == CoinStatsHashType::HASH_SERIALIZED) {
1078 ret.pushKV("hash_serialized_3", stats.hashSerialized.GetHex());
1079 }
1080 if (hash_type == CoinStatsHashType::MUHASH) {
1081 ret.pushKV("muhash", stats.hashSerialized.GetHex());
1082 }
1083 CHECK_NONFATAL(stats.total_amount.has_value());
1084 ret.pushKV("total_amount", ValueFromAmount(stats.total_amount.value()));
1085 if (!stats.index_used) {
1086 ret.pushKV("transactions", static_cast<int64_t>(stats.nTransactions));
1087 ret.pushKV("disk_size", stats.nDiskSize);
1088 } else {
1089 ret.pushKV("total_unspendable_amount", ValueFromAmount(stats.total_unspendable_amount));
1090
1091 CCoinsStats prev_stats{};
1092 if (pindex->nHeight > 0) {
1093 const std::optional<CCoinsStats> maybe_prev_stats = GetUTXOStats(coins_view, *blockman, hash_type, node.rpc_interruption_point, pindex->pprev, index_requested);
1094 if (!maybe_prev_stats) {
1095 throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
1096 }
1097 prev_stats = maybe_prev_stats.value();
1098 }
1099
1100 UniValue block_info(UniValue::VOBJ);
1101 block_info.pushKV("prevout_spent", ValueFromAmount(stats.total_prevout_spent_amount - prev_stats.total_prevout_spent_amount));
1102 block_info.pushKV("coinbase", ValueFromAmount(stats.total_coinbase_amount - prev_stats.total_coinbase_amount));
1103 block_info.pushKV("new_outputs_ex_coinbase", ValueFromAmount(stats.total_new_outputs_ex_coinbase_amount - prev_stats.total_new_outputs_ex_coinbase_amount));
1104 block_info.pushKV("unspendable", ValueFromAmount(stats.total_unspendable_amount - prev_stats.total_unspendable_amount));
1105
1106 UniValue unspendables(UniValue::VOBJ);
1107 unspendables.pushKV("genesis_block", ValueFromAmount(stats.total_unspendables_genesis_block - prev_stats.total_unspendables_genesis_block));
1108 unspendables.pushKV("bip30", ValueFromAmount(stats.total_unspendables_bip30 - prev_stats.total_unspendables_bip30));
1109 unspendables.pushKV("scripts", ValueFromAmount(stats.total_unspendables_scripts - prev_stats.total_unspendables_scripts));
1110 unspendables.pushKV("unclaimed_rewards", ValueFromAmount(stats.total_unspendables_unclaimed_rewards - prev_stats.total_unspendables_unclaimed_rewards));
1111 block_info.pushKV("unspendables", std::move(unspendables));
1112
1113 ret.pushKV("block_info", std::move(block_info));
1114 }
1115 } else {
1116 throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
1117 }
1118 return ret;
1119},
1120 };
1121}
1122
1124{
1125 return RPCHelpMan{
1126 "gettxout",
1127 "Returns details about an unspent transaction output.\n",
1128 {
1129 {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
1130 {"n", RPCArg::Type::NUM, RPCArg::Optional::NO, "vout number"},
1131 {"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."},
1132 },
1133 {
1134 RPCResult{"If the UTXO was not found", RPCResult::Type::NONE, "", ""},
1135 RPCResult{"Otherwise", RPCResult::Type::OBJ, "", "", {
1136 {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
1137 {RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
1138 {RPCResult::Type::STR_AMOUNT, "value", "The transaction value in " + CURRENCY_UNIT},
1139 {RPCResult::Type::OBJ, "scriptPubKey", "", {
1140 {RPCResult::Type::STR, "asm", "Disassembly of the output script"},
1141 {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
1142 {RPCResult::Type::STR_HEX, "hex", "The raw output script bytes, hex-encoded"},
1143 {RPCResult::Type::STR, "type", "The type, eg pubkeyhash"},
1144 {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
1145 }},
1146 {RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
1147 }},
1148 },
1150 "\nGet unspent transactions\n"
1151 + HelpExampleCli("listunspent", "") +
1152 "\nView the details\n"
1153 + HelpExampleCli("gettxout", "\"txid\" 1") +
1154 "\nAs a JSON-RPC call\n"
1155 + HelpExampleRpc("gettxout", "\"txid\", 1")
1156 },
1157 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1158{
1159 NodeContext& node = EnsureAnyNodeContext(request.context);
1161 LOCK(cs_main);
1162
1164
1165 auto hash{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
1166 COutPoint out{hash, request.params[1].getInt<uint32_t>()};
1167 bool fMempool = true;
1168 if (!request.params[2].isNull())
1169 fMempool = request.params[2].get_bool();
1170
1171 Chainstate& active_chainstate = chainman.ActiveChainstate();
1172 CCoinsViewCache* coins_view = &active_chainstate.CoinsTip();
1173
1174 std::optional<Coin> coin;
1175 if (fMempool) {
1176 const CTxMemPool& mempool = EnsureMemPool(node);
1177 LOCK(mempool.cs);
1178 CCoinsViewMemPool view(coins_view, mempool);
1179 if (!mempool.isSpent(out)) coin = view.GetCoin(out);
1180 } else {
1181 coin = coins_view->GetCoin(out);
1182 }
1183 if (!coin) return UniValue::VNULL;
1184
1185 const CBlockIndex* pindex = active_chainstate.m_blockman.LookupBlockIndex(coins_view->GetBestBlock());
1186 ret.pushKV("bestblock", pindex->GetBlockHash().GetHex());
1187 if (coin->nHeight == MEMPOOL_HEIGHT) {
1188 ret.pushKV("confirmations", 0);
1189 } else {
1190 ret.pushKV("confirmations", (int64_t)(pindex->nHeight - coin->nHeight + 1));
1191 }
1192 ret.pushKV("value", ValueFromAmount(coin->out.nValue));
1194 ScriptToUniv(coin->out.scriptPubKey, /*out=*/o, /*include_hex=*/true, /*include_address=*/true);
1195 ret.pushKV("scriptPubKey", std::move(o));
1196 ret.pushKV("coinbase", (bool)coin->fCoinBase);
1197
1198 return ret;
1199},
1200 };
1201}
1202
1204{
1205 return RPCHelpMan{
1206 "verifychain",
1207 "Verifies blockchain database.\n",
1208 {
1209 {"checklevel", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL)},
1210 strprintf("How thorough the block verification is:\n%s", MakeUnorderedList(CHECKLEVEL_DOC))},
1211 {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, 0=all", DEFAULT_CHECKBLOCKS)}, "The number of blocks to check."},
1212 },
1213 RPCResult{
1214 RPCResult::Type::BOOL, "", "Verification finished successfully. If false, check debug.log for reason."},
1216 HelpExampleCli("verifychain", "")
1217 + HelpExampleRpc("verifychain", "")
1218 },
1219 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1220{
1221 const int check_level{request.params[0].isNull() ? DEFAULT_CHECKLEVEL : request.params[0].getInt<int>()};
1222 const int check_depth{request.params[1].isNull() ? DEFAULT_CHECKBLOCKS : request.params[1].getInt<int>()};
1223
1224 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1225 LOCK(cs_main);
1226
1227 Chainstate& active_chainstate = chainman.ActiveChainstate();
1228 return CVerifyDB(chainman.GetNotifications()).VerifyDB(
1229 active_chainstate, chainman.GetParams().GetConsensus(), active_chainstate.CoinsTip(), check_level, check_depth) == VerifyDBResult::SUCCESS;
1230},
1231 };
1232}
1233
1234static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const ChainstateManager& chainman, Consensus::BuriedDeployment dep)
1235{
1236 // For buried deployments.
1237
1238 if (!DeploymentEnabled(chainman, dep)) return;
1239
1241 rv.pushKV("type", "buried");
1242 // getdeploymentinfo reports the softfork as active from when the chain height is
1243 // one below the activation height
1244 rv.pushKV("active", DeploymentActiveAfter(blockindex, chainman, dep));
1245 rv.pushKV("height", chainman.GetConsensus().DeploymentHeight(dep));
1246 softforks.pushKV(DeploymentName(dep), std::move(rv));
1247}
1248
1249static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const ChainstateManager& chainman, Consensus::DeploymentPos id)
1250{
1251 // For BIP9 deployments.
1252 if (!DeploymentEnabled(chainman, id)) return;
1253 if (blockindex == nullptr) return;
1254
1256 BIP9Info info{chainman.m_versionbitscache.Info(*blockindex, chainman.GetConsensus(), id)};
1257 const auto& depparams{chainman.GetConsensus().vDeployments[id]};
1258
1259 // BIP9 parameters
1260 if (info.stats.has_value()) {
1261 bip9.pushKV("bit", depparams.bit);
1262 }
1263 bip9.pushKV("start_time", depparams.nStartTime);
1264 bip9.pushKV("timeout", depparams.nTimeout);
1265 bip9.pushKV("min_activation_height", depparams.min_activation_height);
1266
1267 // BIP9 status
1268 bip9.pushKV("status", info.current_state);
1269 bip9.pushKV("since", info.since);
1270 bip9.pushKV("status_next", info.next_state);
1271
1272 // BIP9 signalling status, if applicable
1273 if (info.stats.has_value()) {
1274 UniValue statsUV(UniValue::VOBJ);
1275 statsUV.pushKV("period", info.stats->period);
1276 statsUV.pushKV("elapsed", info.stats->elapsed);
1277 statsUV.pushKV("count", info.stats->count);
1278 if (info.stats->threshold > 0 || info.stats->possible) {
1279 statsUV.pushKV("threshold", info.stats->threshold);
1280 statsUV.pushKV("possible", info.stats->possible);
1281 }
1282 bip9.pushKV("statistics", std::move(statsUV));
1283
1284 std::string sig;
1285 sig.reserve(info.signalling_blocks.size());
1286 for (const bool s : info.signalling_blocks) {
1287 sig.push_back(s ? '#' : '-');
1288 }
1289 bip9.pushKV("signalling", sig);
1290 }
1291
1293 rv.pushKV("type", "bip9");
1294 bool is_active = false;
1295 if (info.active_since.has_value()) {
1296 rv.pushKV("height", *info.active_since);
1297 is_active = (*info.active_since <= blockindex->nHeight + 1);
1298 }
1299 rv.pushKV("active", is_active);
1300 rv.pushKV("bip9", bip9);
1301 softforks.pushKV(DeploymentName(id), std::move(rv));
1302}
1303
1304// used by rest.cpp:rest_chaininfo, so cannot be static
1306{
1307 return RPCHelpMan{"getblockchaininfo",
1308 "Returns an object containing various state info regarding blockchain processing.\n",
1309 {},
1310 RPCResult{
1311 RPCResult::Type::OBJ, "", "",
1312 {
1313 {RPCResult::Type::STR, "chain", "current network name (" LIST_CHAIN_NAMES ")"},
1314 {RPCResult::Type::NUM, "blocks", "the height of the most-work fully-validated chain. The genesis block has height 0"},
1315 {RPCResult::Type::NUM, "headers", "the current number of headers we have validated"},
1316 {RPCResult::Type::STR, "bestblockhash", "the hash of the currently best block"},
1317 {RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},
1318 {RPCResult::Type::STR_HEX, "target", "The difficulty target"},
1319 {RPCResult::Type::NUM, "difficulty", "the current difficulty"},
1320 {RPCResult::Type::NUM_TIME, "time", "The block time expressed in " + UNIX_EPOCH_TIME},
1321 {RPCResult::Type::NUM_TIME, "mediantime", "The median block time expressed in " + UNIX_EPOCH_TIME},
1322 {RPCResult::Type::NUM, "verificationprogress", "estimate of verification progress [0..1]"},
1323 {RPCResult::Type::BOOL, "initialblockdownload", "(debug information) estimate of whether this node is in Initial Block Download mode"},
1324 {RPCResult::Type::STR_HEX, "chainwork", "total amount of work in active chain, in hexadecimal"},
1325 {RPCResult::Type::NUM, "size_on_disk", "the estimated size of the block and undo files on disk"},
1326 {RPCResult::Type::BOOL, "pruned", "if the blocks are subject to pruning"},
1327 {RPCResult::Type::NUM, "pruneheight", /*optional=*/true, "height of the last block pruned, plus one (only present if pruning is enabled)"},
1328 {RPCResult::Type::BOOL, "automatic_pruning", /*optional=*/true, "whether automatic pruning is enabled (only present if pruning is enabled)"},
1329 {RPCResult::Type::NUM, "prune_target_size", /*optional=*/true, "the target size used by pruning (only present if automatic pruning is enabled)"},
1330 {RPCResult::Type::STR_HEX, "signet_challenge", /*optional=*/true, "the block challenge (aka. block script), in hexadecimal (only present if the current network is a signet)"},
1331 (IsDeprecatedRPCEnabled("warnings") ?
1332 RPCResult{RPCResult::Type::STR, "warnings", "any network and blockchain warnings (DEPRECATED)"} :
1333 RPCResult{RPCResult::Type::ARR, "warnings", "any network and blockchain warnings (run with `-deprecatedrpc=warnings` to return the latest warning as a single string)",
1334 {
1335 {RPCResult::Type::STR, "", "warning"},
1336 }
1337 }
1338 ),
1339 }},
1341 HelpExampleCli("getblockchaininfo", "")
1342 + HelpExampleRpc("getblockchaininfo", "")
1343 },
1344 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1345{
1346 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1347 LOCK(cs_main);
1348 Chainstate& active_chainstate = chainman.ActiveChainstate();
1349
1350 const CBlockIndex& tip{*CHECK_NONFATAL(active_chainstate.m_chain.Tip())};
1351 const int height{tip.nHeight};
1353 obj.pushKV("chain", chainman.GetParams().GetChainTypeString());
1354 obj.pushKV("blocks", height);
1355 obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
1356 obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex());
1357 obj.pushKV("bits", strprintf("%08x", tip.nBits));
1358 obj.pushKV("target", GetTarget(tip, chainman.GetConsensus().powLimit).GetHex());
1359 obj.pushKV("difficulty", GetDifficulty(tip));
1360 obj.pushKV("time", tip.GetBlockTime());
1361 obj.pushKV("mediantime", tip.GetMedianTimePast());
1362 obj.pushKV("verificationprogress", chainman.GuessVerificationProgress(&tip));
1363 obj.pushKV("initialblockdownload", chainman.IsInitialBlockDownload());
1364 obj.pushKV("chainwork", tip.nChainWork.GetHex());
1365 obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage());
1366 obj.pushKV("pruned", chainman.m_blockman.IsPruneMode());
1367 if (chainman.m_blockman.IsPruneMode()) {
1368 const auto prune_height{GetPruneHeight(chainman.m_blockman, active_chainstate.m_chain)};
1369 obj.pushKV("pruneheight", prune_height ? prune_height.value() + 1 : 0);
1370
1371 const bool automatic_pruning{chainman.m_blockman.GetPruneTarget() != BlockManager::PRUNE_TARGET_MANUAL};
1372 obj.pushKV("automatic_pruning", automatic_pruning);
1373 if (automatic_pruning) {
1374 obj.pushKV("prune_target_size", chainman.m_blockman.GetPruneTarget());
1375 }
1376 }
1377 if (chainman.GetParams().GetChainType() == ChainType::SIGNET) {
1378 const std::vector<uint8_t>& signet_challenge =
1380 obj.pushKV("signet_challenge", HexStr(signet_challenge));
1381 }
1382
1383 NodeContext& node = EnsureAnyNodeContext(request.context);
1384 obj.pushKV("warnings", node::GetWarningsForRpc(*CHECK_NONFATAL(node.warnings), IsDeprecatedRPCEnabled("warnings")));
1385 return obj;
1386},
1387 };
1388}
1389
1390namespace {
1391const std::vector<RPCResult> RPCHelpForDeployment{
1392 {RPCResult::Type::STR, "type", "one of \"buried\", \"bip9\""},
1393 {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)"},
1394 {RPCResult::Type::BOOL, "active", "true if the rules are enforced for the mempool and the next block"},
1395 {RPCResult::Type::OBJ, "bip9", /*optional=*/true, "status of bip9 softforks (only for \"bip9\" type)",
1396 {
1397 {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)"},
1398 {RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"},
1399 {RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"},
1400 {RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"},
1401 {RPCResult::Type::STR, "status", "status of deployment at specified block (one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\")"},
1402 {RPCResult::Type::NUM, "since", "height of the first block to which the status applies"},
1403 {RPCResult::Type::STR, "status_next", "status of deployment at the next block"},
1404 {RPCResult::Type::OBJ, "statistics", /*optional=*/true, "numeric statistics about signalling for a softfork (only for \"started\" and \"locked_in\" status)",
1405 {
1406 {RPCResult::Type::NUM, "period", "the length in blocks of the signalling period"},
1407 {RPCResult::Type::NUM, "threshold", /*optional=*/true, "the number of blocks with the version bit set required to activate the feature (only for \"started\" status)"},
1408 {RPCResult::Type::NUM, "elapsed", "the number of blocks elapsed since the beginning of the current period"},
1409 {RPCResult::Type::NUM, "count", "the number of blocks with the version bit set in the current period"},
1410 {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)"},
1411 }},
1412 {RPCResult::Type::STR, "signalling", /*optional=*/true, "indicates blocks that signalled with a # and blocks that did not with a -"},
1413 }},
1414};
1415
1416UniValue DeploymentInfo(const CBlockIndex* blockindex, const ChainstateManager& chainman)
1417{
1418 UniValue softforks(UniValue::VOBJ);
1419 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_HEIGHTINCB);
1420 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_DERSIG);
1421 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_CLTV);
1422 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_CSV);
1423 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_SEGWIT);
1424 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TESTDUMMY);
1425 SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TAPROOT);
1426 return softforks;
1427}
1428} // anon namespace
1429
1431{
1432 return RPCHelpMan{"getdeploymentinfo",
1433 "Returns an object containing various state info regarding deployments of consensus changes.",
1434 {
1435 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Default{"hash of current chain tip"}, "The block hash at which to query deployment state"},
1436 },
1437 RPCResult{
1438 RPCResult::Type::OBJ, "", "", {
1439 {RPCResult::Type::STR, "hash", "requested block hash (or tip)"},
1440 {RPCResult::Type::NUM, "height", "requested block height (or tip)"},
1441 {RPCResult::Type::OBJ_DYN, "deployments", "", {
1442 {RPCResult::Type::OBJ, "xxxx", "name of the deployment", RPCHelpForDeployment}
1443 }},
1444 }
1445 },
1446 RPCExamples{ HelpExampleCli("getdeploymentinfo", "") + HelpExampleRpc("getdeploymentinfo", "") },
1447 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1448 {
1449 const ChainstateManager& chainman = EnsureAnyChainman(request.context);
1450 LOCK(cs_main);
1451 const Chainstate& active_chainstate = chainman.ActiveChainstate();
1452
1453 const CBlockIndex* blockindex;
1454 if (request.params[0].isNull()) {
1455 blockindex = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
1456 } else {
1457 const uint256 hash(ParseHashV(request.params[0], "blockhash"));
1458 blockindex = chainman.m_blockman.LookupBlockIndex(hash);
1459 if (!blockindex) {
1460 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1461 }
1462 }
1463
1464 UniValue deploymentinfo(UniValue::VOBJ);
1465 deploymentinfo.pushKV("hash", blockindex->GetBlockHash().ToString());
1466 deploymentinfo.pushKV("height", blockindex->nHeight);
1467 deploymentinfo.pushKV("deployments", DeploymentInfo(blockindex, chainman));
1468 return deploymentinfo;
1469 },
1470 };
1471}
1472
1475{
1476 bool operator()(const CBlockIndex* a, const CBlockIndex* b) const
1477 {
1478 /* Make sure that unequal blocks with the same height do not compare
1479 equal. Use the pointers themselves to make a distinction. */
1480
1481 if (a->nHeight != b->nHeight)
1482 return (a->nHeight > b->nHeight);
1483
1484 return a < b;
1485 }
1486};
1487
1489{
1490 return RPCHelpMan{"getchaintips",
1491 "Return information about all known tips in the block tree,"
1492 " including the main chain as well as orphaned branches.\n",
1493 {},
1494 RPCResult{
1495 RPCResult::Type::ARR, "", "",
1496 {{RPCResult::Type::OBJ, "", "",
1497 {
1498 {RPCResult::Type::NUM, "height", "height of the chain tip"},
1499 {RPCResult::Type::STR_HEX, "hash", "block hash of the tip"},
1500 {RPCResult::Type::NUM, "branchlen", "zero for main chain, otherwise length of branch connecting the tip to the main chain"},
1501 {RPCResult::Type::STR, "status", "status of the chain, \"active\" for the main chain\n"
1502 "Possible values for status:\n"
1503 "1. \"invalid\" This branch contains at least one invalid block\n"
1504 "2. \"headers-only\" Not all blocks for this branch are available, but the headers are valid\n"
1505 "3. \"valid-headers\" All blocks are available for this branch, but they were never fully validated\n"
1506 "4. \"valid-fork\" This branch is not part of the active chain, but is fully validated\n"
1507 "5. \"active\" This is the tip of the active main chain, which is certainly valid"},
1508 }}}},
1510 HelpExampleCli("getchaintips", "")
1511 + HelpExampleRpc("getchaintips", "")
1512 },
1513 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1514{
1515 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1516 LOCK(cs_main);
1517 CChain& active_chain = chainman.ActiveChain();
1518
1519 /*
1520 * Idea: The set of chain tips is the active chain tip, plus orphan blocks which do not have another orphan building off of them.
1521 * Algorithm:
1522 * - Make one pass through BlockIndex(), picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers.
1523 * - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip.
1524 * - Add the active chain tip
1525 */
1526 std::set<const CBlockIndex*, CompareBlocksByHeight> setTips;
1527 std::set<const CBlockIndex*> setOrphans;
1528 std::set<const CBlockIndex*> setPrevs;
1529
1530 for (const auto& [_, block_index] : chainman.BlockIndex()) {
1531 if (!active_chain.Contains(&block_index)) {
1532 setOrphans.insert(&block_index);
1533 setPrevs.insert(block_index.pprev);
1534 }
1535 }
1536
1537 for (std::set<const CBlockIndex*>::iterator it = setOrphans.begin(); it != setOrphans.end(); ++it) {
1538 if (setPrevs.erase(*it) == 0) {
1539 setTips.insert(*it);
1540 }
1541 }
1542
1543 // Always report the currently active tip.
1544 setTips.insert(active_chain.Tip());
1545
1546 /* Construct the output array. */
1548 for (const CBlockIndex* block : setTips) {
1550 obj.pushKV("height", block->nHeight);
1551 obj.pushKV("hash", block->phashBlock->GetHex());
1552
1553 const int branchLen = block->nHeight - active_chain.FindFork(block)->nHeight;
1554 obj.pushKV("branchlen", branchLen);
1555
1556 std::string status;
1557 if (active_chain.Contains(block)) {
1558 // This block is part of the currently active chain.
1559 status = "active";
1560 } else if (block->nStatus & BLOCK_FAILED_MASK) {
1561 // This block or one of its ancestors is invalid.
1562 status = "invalid";
1563 } else if (!block->HaveNumChainTxs()) {
1564 // This block cannot be connected because full block data for it or one of its parents is missing.
1565 status = "headers-only";
1566 } else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {
1567 // This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.
1568 status = "valid-fork";
1569 } else if (block->IsValid(BLOCK_VALID_TREE)) {
1570 // The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.
1571 status = "valid-headers";
1572 } else {
1573 // No clue.
1574 status = "unknown";
1575 }
1576 obj.pushKV("status", status);
1577
1578 res.push_back(std::move(obj));
1579 }
1580
1581 return res;
1582},
1583 };
1584}
1585
1587{
1588 return RPCHelpMan{
1589 "preciousblock",
1590 "Treats a block as if it were received before others with the same work.\n"
1591 "\nA later preciousblock call can override the effect of an earlier one.\n"
1592 "\nThe effects of preciousblock are not retained across restarts.\n",
1593 {
1594 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as precious"},
1595 },
1598 HelpExampleCli("preciousblock", "\"blockhash\"")
1599 + HelpExampleRpc("preciousblock", "\"blockhash\"")
1600 },
1601 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1602{
1603 uint256 hash(ParseHashV(request.params[0], "blockhash"));
1604 CBlockIndex* pblockindex;
1605
1606 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1607 {
1608 LOCK(cs_main);
1609 pblockindex = chainman.m_blockman.LookupBlockIndex(hash);
1610 if (!pblockindex) {
1611 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1612 }
1613 }
1614
1616 chainman.ActiveChainstate().PreciousBlock(state, pblockindex);
1617
1618 if (!state.IsValid()) {
1620 }
1621
1622 return UniValue::VNULL;
1623},
1624 };
1625}
1626
1627void InvalidateBlock(ChainstateManager& chainman, const uint256 block_hash) {
1629 CBlockIndex* pblockindex;
1630 {
1631 LOCK(chainman.GetMutex());
1632 pblockindex = chainman.m_blockman.LookupBlockIndex(block_hash);
1633 if (!pblockindex) {
1634 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1635 }
1636 }
1637 chainman.ActiveChainstate().InvalidateBlock(state, pblockindex);
1638
1639 if (state.IsValid()) {
1640 chainman.ActiveChainstate().ActivateBestChain(state);
1641 }
1642
1643 if (!state.IsValid()) {
1645 }
1646}
1647
1649{
1650 return RPCHelpMan{
1651 "invalidateblock",
1652 "Permanently marks a block as invalid, as if it violated a consensus rule.\n",
1653 {
1654 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as invalid"},
1655 },
1658 HelpExampleCli("invalidateblock", "\"blockhash\"")
1659 + HelpExampleRpc("invalidateblock", "\"blockhash\"")
1660 },
1661 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1662{
1663 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1664 uint256 hash(ParseHashV(request.params[0], "blockhash"));
1665
1666 InvalidateBlock(chainman, hash);
1667
1668 return UniValue::VNULL;
1669},
1670 };
1671}
1672
1673void ReconsiderBlock(ChainstateManager& chainman, uint256 block_hash) {
1674 {
1675 LOCK(chainman.GetMutex());
1676 CBlockIndex* pblockindex = chainman.m_blockman.LookupBlockIndex(block_hash);
1677 if (!pblockindex) {
1678 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1679 }
1680
1681 chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex);
1682 chainman.RecalculateBestHeader();
1683 }
1684
1686 chainman.ActiveChainstate().ActivateBestChain(state);
1687
1688 if (!state.IsValid()) {
1690 }
1691}
1692
1694{
1695 return RPCHelpMan{
1696 "reconsiderblock",
1697 "Removes invalidity status of a block, its ancestors and its descendants, reconsider them for activation.\n"
1698 "This can be used to undo the effects of invalidateblock.\n",
1699 {
1700 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to reconsider"},
1701 },
1704 HelpExampleCli("reconsiderblock", "\"blockhash\"")
1705 + HelpExampleRpc("reconsiderblock", "\"blockhash\"")
1706 },
1707 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1708{
1709 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1710 uint256 hash(ParseHashV(request.params[0], "blockhash"));
1711
1712 ReconsiderBlock(chainman, hash);
1713
1714 return UniValue::VNULL;
1715},
1716 };
1717}
1718
1720{
1721 return RPCHelpMan{
1722 "getchaintxstats",
1723 "Compute statistics about the total number and rate of transactions in the chain.\n",
1724 {
1725 {"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{"one month"}, "Size of the window in number of blocks"},
1726 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"chain tip"}, "The hash of the block that ends the window."},
1727 },
1728 RPCResult{
1729 RPCResult::Type::OBJ, "", "",
1730 {
1731 {RPCResult::Type::NUM_TIME, "time", "The timestamp for the final block in the window, expressed in " + UNIX_EPOCH_TIME},
1732 {RPCResult::Type::NUM, "txcount", /*optional=*/true,
1733 "The total number of transactions in the chain up to that point, if known. "
1734 "It may be unknown when using assumeutxo."},
1735 {RPCResult::Type::STR_HEX, "window_final_block_hash", "The hash of the final block in the window"},
1736 {RPCResult::Type::NUM, "window_final_block_height", "The height of the final block in the window."},
1737 {RPCResult::Type::NUM, "window_block_count", "Size of the window in number of blocks"},
1738 {RPCResult::Type::NUM, "window_interval", /*optional=*/true, "The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0"},
1739 {RPCResult::Type::NUM, "window_tx_count", /*optional=*/true,
1740 "The number of transactions in the window. "
1741 "Only returned if \"window_block_count\" is > 0 and if txcount exists for the start and end of the window."},
1742 {RPCResult::Type::NUM, "txrate", /*optional=*/true,
1743 "The average rate of transactions per second in the window. "
1744 "Only returned if \"window_interval\" is > 0 and if window_tx_count exists."},
1745 }},
1747 HelpExampleCli("getchaintxstats", "")
1748 + HelpExampleRpc("getchaintxstats", "2016")
1749 },
1750 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1751{
1752 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1753 const CBlockIndex* pindex;
1754 int blockcount = 30 * 24 * 60 * 60 / chainman.GetParams().GetConsensus().nPowTargetSpacing; // By default: 1 month
1755
1756 if (request.params[1].isNull()) {
1757 LOCK(cs_main);
1758 pindex = chainman.ActiveChain().Tip();
1759 } else {
1760 uint256 hash(ParseHashV(request.params[1], "blockhash"));
1761 LOCK(cs_main);
1762 pindex = chainman.m_blockman.LookupBlockIndex(hash);
1763 if (!pindex) {
1764 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1765 }
1766 if (!chainman.ActiveChain().Contains(pindex)) {
1767 throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain");
1768 }
1769 }
1770
1771 CHECK_NONFATAL(pindex != nullptr);
1772
1773 if (request.params[0].isNull()) {
1774 blockcount = std::max(0, std::min(blockcount, pindex->nHeight - 1));
1775 } else {
1776 blockcount = request.params[0].getInt<int>();
1777
1778 if (blockcount < 0 || (blockcount > 0 && blockcount >= pindex->nHeight)) {
1779 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 0 and the block's height - 1");
1780 }
1781 }
1782
1783 const CBlockIndex& past_block{*CHECK_NONFATAL(pindex->GetAncestor(pindex->nHeight - blockcount))};
1784 const int64_t nTimeDiff{pindex->GetMedianTimePast() - past_block.GetMedianTimePast()};
1785
1787 ret.pushKV("time", (int64_t)pindex->nTime);
1788 if (pindex->m_chain_tx_count) {
1789 ret.pushKV("txcount", pindex->m_chain_tx_count);
1790 }
1791 ret.pushKV("window_final_block_hash", pindex->GetBlockHash().GetHex());
1792 ret.pushKV("window_final_block_height", pindex->nHeight);
1793 ret.pushKV("window_block_count", blockcount);
1794 if (blockcount > 0) {
1795 ret.pushKV("window_interval", nTimeDiff);
1796 if (pindex->m_chain_tx_count != 0 && past_block.m_chain_tx_count != 0) {
1797 const auto window_tx_count = pindex->m_chain_tx_count - past_block.m_chain_tx_count;
1798 ret.pushKV("window_tx_count", window_tx_count);
1799 if (nTimeDiff > 0) {
1800 ret.pushKV("txrate", double(window_tx_count) / nTimeDiff);
1801 }
1802 }
1803 }
1804
1805 return ret;
1806},
1807 };
1808}
1809
1810template<typename T>
1811static T CalculateTruncatedMedian(std::vector<T>& scores)
1812{
1813 size_t size = scores.size();
1814 if (size == 0) {
1815 return 0;
1816 }
1817
1818 std::sort(scores.begin(), scores.end());
1819 if (size % 2 == 0) {
1820 return (scores[size / 2 - 1] + scores[size / 2]) / 2;
1821 } else {
1822 return scores[size / 2];
1823 }
1824}
1825
1826void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight)
1827{
1828 if (scores.empty()) {
1829 return;
1830 }
1831
1832 std::sort(scores.begin(), scores.end());
1833
1834 // 10th, 25th, 50th, 75th, and 90th percentile weight units.
1835 const double weights[NUM_GETBLOCKSTATS_PERCENTILES] = {
1836 total_weight / 10.0, total_weight / 4.0, total_weight / 2.0, (total_weight * 3.0) / 4.0, (total_weight * 9.0) / 10.0
1837 };
1838
1839 int64_t next_percentile_index = 0;
1840 int64_t cumulative_weight = 0;
1841 for (const auto& element : scores) {
1842 cumulative_weight += element.second;
1843 while (next_percentile_index < NUM_GETBLOCKSTATS_PERCENTILES && cumulative_weight >= weights[next_percentile_index]) {
1844 result[next_percentile_index] = element.first;
1845 ++next_percentile_index;
1846 }
1847 }
1848
1849 // Fill any remaining percentiles with the last value.
1850 for (int64_t i = next_percentile_index; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {
1851 result[i] = scores.back().first;
1852 }
1853}
1854
1855template<typename T>
1856static inline bool SetHasKeys(const std::set<T>& set) {return false;}
1857template<typename T, typename Tk, typename... Args>
1858static inline bool SetHasKeys(const std::set<T>& set, const Tk& key, const Args&... args)
1859{
1860 return (set.count(key) != 0) || SetHasKeys(set, args...);
1861}
1862
1863// outpoint (needed for the utxo index) + nHeight + fCoinBase
1864static constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool);
1865
1867{
1868 return RPCHelpMan{
1869 "getblockstats",
1870 "Compute per block statistics for a given window. All amounts are in satoshis.\n"
1871 "It won't work for some heights with pruning.\n",
1872 {
1873 {"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block",
1875 .skip_type_check = true,
1876 .type_str = {"", "string or numeric"},
1877 }},
1878 {"stats", RPCArg::Type::ARR, RPCArg::DefaultHint{"all values"}, "Values to plot (see result below)",
1879 {
1880 {"height", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
1881 {"time", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Selected statistic"},
1882 },
1884 },
1885 RPCResult{
1886 RPCResult::Type::OBJ, "", "",
1887 {
1888 {RPCResult::Type::NUM, "avgfee", /*optional=*/true, "Average fee in the block"},
1889 {RPCResult::Type::NUM, "avgfeerate", /*optional=*/true, "Average feerate (in satoshis per virtual byte)"},
1890 {RPCResult::Type::NUM, "avgtxsize", /*optional=*/true, "Average transaction size"},
1891 {RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "The block hash (to check for potential reorgs)"},
1892 {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)",
1893 {
1894 {RPCResult::Type::NUM, "10th_percentile_feerate", "The 10th percentile feerate"},
1895 {RPCResult::Type::NUM, "25th_percentile_feerate", "The 25th percentile feerate"},
1896 {RPCResult::Type::NUM, "50th_percentile_feerate", "The 50th percentile feerate"},
1897 {RPCResult::Type::NUM, "75th_percentile_feerate", "The 75th percentile feerate"},
1898 {RPCResult::Type::NUM, "90th_percentile_feerate", "The 90th percentile feerate"},
1899 }},
1900 {RPCResult::Type::NUM, "height", /*optional=*/true, "The height of the block"},
1901 {RPCResult::Type::NUM, "ins", /*optional=*/true, "The number of inputs (excluding coinbase)"},
1902 {RPCResult::Type::NUM, "maxfee", /*optional=*/true, "Maximum fee in the block"},
1903 {RPCResult::Type::NUM, "maxfeerate", /*optional=*/true, "Maximum feerate (in satoshis per virtual byte)"},
1904 {RPCResult::Type::NUM, "maxtxsize", /*optional=*/true, "Maximum transaction size"},
1905 {RPCResult::Type::NUM, "medianfee", /*optional=*/true, "Truncated median fee in the block"},
1906 {RPCResult::Type::NUM, "mediantime", /*optional=*/true, "The block median time past"},
1907 {RPCResult::Type::NUM, "mediantxsize", /*optional=*/true, "Truncated median transaction size"},
1908 {RPCResult::Type::NUM, "minfee", /*optional=*/true, "Minimum fee in the block"},
1909 {RPCResult::Type::NUM, "minfeerate", /*optional=*/true, "Minimum feerate (in satoshis per virtual byte)"},
1910 {RPCResult::Type::NUM, "mintxsize", /*optional=*/true, "Minimum transaction size"},
1911 {RPCResult::Type::NUM, "outs", /*optional=*/true, "The number of outputs"},
1912 {RPCResult::Type::NUM, "subsidy", /*optional=*/true, "The block subsidy"},
1913 {RPCResult::Type::NUM, "swtotal_size", /*optional=*/true, "Total size of all segwit transactions"},
1914 {RPCResult::Type::NUM, "swtotal_weight", /*optional=*/true, "Total weight of all segwit transactions"},
1915 {RPCResult::Type::NUM, "swtxs", /*optional=*/true, "The number of segwit transactions"},
1916 {RPCResult::Type::NUM, "time", /*optional=*/true, "The block time"},
1917 {RPCResult::Type::NUM, "total_out", /*optional=*/true, "Total amount in all outputs (excluding coinbase and thus reward [ie subsidy + totalfee])"},
1918 {RPCResult::Type::NUM, "total_size", /*optional=*/true, "Total size of all non-coinbase transactions"},
1919 {RPCResult::Type::NUM, "total_weight", /*optional=*/true, "Total weight of all non-coinbase transactions"},
1920 {RPCResult::Type::NUM, "totalfee", /*optional=*/true, "The fee total"},
1921 {RPCResult::Type::NUM, "txs", /*optional=*/true, "The number of transactions (including coinbase)"},
1922 {RPCResult::Type::NUM, "utxo_increase", /*optional=*/true, "The increase/decrease in the number of unspent outputs (not discounting op_return and similar)"},
1923 {RPCResult::Type::NUM, "utxo_size_inc", /*optional=*/true, "The increase/decrease in size for the utxo index (not discounting op_return and similar)"},
1924 {RPCResult::Type::NUM, "utxo_increase_actual", /*optional=*/true, "The increase/decrease in the number of unspent outputs, not counting unspendables"},
1925 {RPCResult::Type::NUM, "utxo_size_inc_actual", /*optional=*/true, "The increase/decrease in size for the utxo index, not counting unspendables"},
1926 }},
1928 HelpExampleCli("getblockstats", R"('"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"' '["minfeerate","avgfeerate"]')") +
1929 HelpExampleCli("getblockstats", R"(1000 '["minfeerate","avgfeerate"]')") +
1930 HelpExampleRpc("getblockstats", R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") +
1931 HelpExampleRpc("getblockstats", R"(1000, ["minfeerate","avgfeerate"])")
1932 },
1933 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1934{
1935 ChainstateManager& chainman = EnsureAnyChainman(request.context);
1936 const CBlockIndex& pindex{*CHECK_NONFATAL(ParseHashOrHeight(request.params[0], chainman))};
1937
1938 std::set<std::string> stats;
1939 if (!request.params[1].isNull()) {
1940 const UniValue stats_univalue = request.params[1].get_array();
1941 for (unsigned int i = 0; i < stats_univalue.size(); i++) {
1942 const std::string stat = stats_univalue[i].get_str();
1943 stats.insert(stat);
1944 }
1945 }
1946
1947 const CBlock& block = GetBlockChecked(chainman.m_blockman, pindex);
1948 const CBlockUndo& blockUndo = GetUndoChecked(chainman.m_blockman, pindex);
1949
1950 const bool do_all = stats.size() == 0; // Calculate everything if nothing selected (default)
1951 const bool do_mediantxsize = do_all || stats.count("mediantxsize") != 0;
1952 const bool do_medianfee = do_all || stats.count("medianfee") != 0;
1953 const bool do_feerate_percentiles = do_all || stats.count("feerate_percentiles") != 0;
1954 const bool loop_inputs = do_all || do_medianfee || do_feerate_percentiles ||
1955 SetHasKeys(stats, "utxo_increase", "utxo_increase_actual", "utxo_size_inc", "utxo_size_inc_actual", "totalfee", "avgfee", "avgfeerate", "minfee", "maxfee", "minfeerate", "maxfeerate");
1956 const bool loop_outputs = do_all || loop_inputs || stats.count("total_out");
1957 const bool do_calculate_size = do_mediantxsize ||
1958 SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize", "maxtxsize", "swtotal_size");
1959 const bool do_calculate_weight = do_all || SetHasKeys(stats, "total_weight", "avgfeerate", "swtotal_weight", "avgfeerate", "feerate_percentiles", "minfeerate", "maxfeerate");
1960 const bool do_calculate_sw = do_all || SetHasKeys(stats, "swtxs", "swtotal_size", "swtotal_weight");
1961
1962 CAmount maxfee = 0;
1963 CAmount maxfeerate = 0;
1964 CAmount minfee = MAX_MONEY;
1965 CAmount minfeerate = MAX_MONEY;
1966 CAmount total_out = 0;
1967 CAmount totalfee = 0;
1968 int64_t inputs = 0;
1969 int64_t maxtxsize = 0;
1970 int64_t mintxsize = MAX_BLOCK_SERIALIZED_SIZE;
1971 int64_t outputs = 0;
1972 int64_t swtotal_size = 0;
1973 int64_t swtotal_weight = 0;
1974 int64_t swtxs = 0;
1975 int64_t total_size = 0;
1976 int64_t total_weight = 0;
1977 int64_t utxos = 0;
1978 int64_t utxo_size_inc = 0;
1979 int64_t utxo_size_inc_actual = 0;
1980 std::vector<CAmount> fee_array;
1981 std::vector<std::pair<CAmount, int64_t>> feerate_array;
1982 std::vector<int64_t> txsize_array;
1983
1984 for (size_t i = 0; i < block.vtx.size(); ++i) {
1985 const auto& tx = block.vtx.at(i);
1986 outputs += tx->vout.size();
1987
1988 CAmount tx_total_out = 0;
1989 if (loop_outputs) {
1990 for (const CTxOut& out : tx->vout) {
1991 tx_total_out += out.nValue;
1992
1993 size_t out_size = GetSerializeSize(out) + PER_UTXO_OVERHEAD;
1994 utxo_size_inc += out_size;
1995
1996 // The Genesis block and the repeated BIP30 block coinbases don't change the UTXO
1997 // set counts, so they have to be excluded from the statistics
1998 if (pindex.nHeight == 0 || (IsBIP30Repeat(pindex) && tx->IsCoinBase())) continue;
1999 // Skip unspendable outputs since they are not included in the UTXO set
2000 if (out.scriptPubKey.IsUnspendable()) continue;
2001
2002 ++utxos;
2003 utxo_size_inc_actual += out_size;
2004 }
2005 }
2006
2007 if (tx->IsCoinBase()) {
2008 continue;
2009 }
2010
2011 inputs += tx->vin.size(); // Don't count coinbase's fake input
2012 total_out += tx_total_out; // Don't count coinbase reward
2013
2014 int64_t tx_size = 0;
2015 if (do_calculate_size) {
2016
2017 tx_size = tx->GetTotalSize();
2018 if (do_mediantxsize) {
2019 txsize_array.push_back(tx_size);
2020 }
2021 maxtxsize = std::max(maxtxsize, tx_size);
2022 mintxsize = std::min(mintxsize, tx_size);
2023 total_size += tx_size;
2024 }
2025
2026 int64_t weight = 0;
2027 if (do_calculate_weight) {
2028 weight = GetTransactionWeight(*tx);
2029 total_weight += weight;
2030 }
2031
2032 if (do_calculate_sw && tx->HasWitness()) {
2033 ++swtxs;
2034 swtotal_size += tx_size;
2035 swtotal_weight += weight;
2036 }
2037
2038 if (loop_inputs) {
2039 CAmount tx_total_in = 0;
2040 const auto& txundo = blockUndo.vtxundo.at(i - 1);
2041 for (const Coin& coin: txundo.vprevout) {
2042 const CTxOut& prevoutput = coin.out;
2043
2044 tx_total_in += prevoutput.nValue;
2045 size_t prevout_size = GetSerializeSize(prevoutput) + PER_UTXO_OVERHEAD;
2046 utxo_size_inc -= prevout_size;
2047 utxo_size_inc_actual -= prevout_size;
2048 }
2049
2050 CAmount txfee = tx_total_in - tx_total_out;
2051 CHECK_NONFATAL(MoneyRange(txfee));
2052 if (do_medianfee) {
2053 fee_array.push_back(txfee);
2054 }
2055 maxfee = std::max(maxfee, txfee);
2056 minfee = std::min(minfee, txfee);
2057 totalfee += txfee;
2058
2059 // New feerate uses satoshis per virtual byte instead of per serialized byte
2060 CAmount feerate = weight ? (txfee * WITNESS_SCALE_FACTOR) / weight : 0;
2061 if (do_feerate_percentiles) {
2062 feerate_array.emplace_back(feerate, weight);
2063 }
2064 maxfeerate = std::max(maxfeerate, feerate);
2065 minfeerate = std::min(minfeerate, feerate);
2066 }
2067 }
2068
2069 CAmount feerate_percentiles[NUM_GETBLOCKSTATS_PERCENTILES] = { 0 };
2070 CalculatePercentilesByWeight(feerate_percentiles, feerate_array, total_weight);
2071
2072 UniValue feerates_res(UniValue::VARR);
2073 for (int64_t i = 0; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {
2074 feerates_res.push_back(feerate_percentiles[i]);
2075 }
2076
2077 UniValue ret_all(UniValue::VOBJ);
2078 ret_all.pushKV("avgfee", (block.vtx.size() > 1) ? totalfee / (block.vtx.size() - 1) : 0);
2079 ret_all.pushKV("avgfeerate", total_weight ? (totalfee * WITNESS_SCALE_FACTOR) / total_weight : 0); // Unit: sat/vbyte
2080 ret_all.pushKV("avgtxsize", (block.vtx.size() > 1) ? total_size / (block.vtx.size() - 1) : 0);
2081 ret_all.pushKV("blockhash", pindex.GetBlockHash().GetHex());
2082 ret_all.pushKV("feerate_percentiles", std::move(feerates_res));
2083 ret_all.pushKV("height", (int64_t)pindex.nHeight);
2084 ret_all.pushKV("ins", inputs);
2085 ret_all.pushKV("maxfee", maxfee);
2086 ret_all.pushKV("maxfeerate", maxfeerate);
2087 ret_all.pushKV("maxtxsize", maxtxsize);
2088 ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
2089 ret_all.pushKV("mediantime", pindex.GetMedianTimePast());
2090 ret_all.pushKV("mediantxsize", CalculateTruncatedMedian(txsize_array));
2091 ret_all.pushKV("minfee", (minfee == MAX_MONEY) ? 0 : minfee);
2092 ret_all.pushKV("minfeerate", (minfeerate == MAX_MONEY) ? 0 : minfeerate);
2093 ret_all.pushKV("mintxsize", mintxsize == MAX_BLOCK_SERIALIZED_SIZE ? 0 : mintxsize);
2094 ret_all.pushKV("outs", outputs);
2095 ret_all.pushKV("subsidy", GetBlockSubsidy(pindex.nHeight, chainman.GetParams().GetConsensus()));
2096 ret_all.pushKV("swtotal_size", swtotal_size);
2097 ret_all.pushKV("swtotal_weight", swtotal_weight);
2098 ret_all.pushKV("swtxs", swtxs);
2099 ret_all.pushKV("time", pindex.GetBlockTime());
2100 ret_all.pushKV("total_out", total_out);
2101 ret_all.pushKV("total_size", total_size);
2102 ret_all.pushKV("total_weight", total_weight);
2103 ret_all.pushKV("totalfee", totalfee);
2104 ret_all.pushKV("txs", (int64_t)block.vtx.size());
2105 ret_all.pushKV("utxo_increase", outputs - inputs);
2106 ret_all.pushKV("utxo_size_inc", utxo_size_inc);
2107 ret_all.pushKV("utxo_increase_actual", utxos - inputs);
2108 ret_all.pushKV("utxo_size_inc_actual", utxo_size_inc_actual);
2109
2110 if (do_all) {
2111 return ret_all;
2112 }
2113
2115 for (const std::string& stat : stats) {
2116 const UniValue& value = ret_all[stat];
2117 if (value.isNull()) {
2118 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid selected statistic '%s'", stat));
2119 }
2120 ret.pushKV(stat, value);
2121 }
2122 return ret;
2123},
2124 };
2125}
2126
2127namespace {
2129bool 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)
2130{
2131 scan_progress = 0;
2132 count = 0;
2133 while (cursor->Valid()) {
2134 COutPoint key;
2135 Coin coin;
2136 if (!cursor->GetKey(key) || !cursor->GetValue(coin)) return false;
2137 if (++count % 8192 == 0) {
2138 interruption_point();
2139 if (should_abort) {
2140 // allow to abort the scan via the abort reference
2141 return false;
2142 }
2143 }
2144 if (count % 256 == 0) {
2145 // update progress reference every 256 item
2146 uint32_t high = 0x100 * *UCharCast(key.hash.begin()) + *(UCharCast(key.hash.begin()) + 1);
2147 scan_progress = (int)(high * 100.0 / 65536.0 + 0.5);
2148 }
2149 if (needles.count(coin.out.scriptPubKey)) {
2150 out_results.emplace(key, coin);
2151 }
2152 cursor->Next();
2153 }
2154 scan_progress = 100;
2155 return true;
2156}
2157} // namespace
2158
2160static std::atomic<int> g_scan_progress;
2161static std::atomic<bool> g_scan_in_progress;
2162static std::atomic<bool> g_should_abort_scan;
2164{
2165private:
2166 bool m_could_reserve{false};
2167public:
2168 explicit CoinsViewScanReserver() = default;
2169
2170 bool reserve() {
2172 if (g_scan_in_progress.exchange(true)) {
2173 return false;
2174 }
2176 m_could_reserve = true;
2177 return true;
2178 }
2179
2181 if (m_could_reserve) {
2182 g_scan_in_progress = false;
2183 g_scan_progress = 0;
2184 }
2185 }
2186};
2187
2188static const auto scan_action_arg_desc = RPCArg{
2189 "action", RPCArg::Type::STR, RPCArg::Optional::NO, "The action to execute\n"
2190 "\"start\" for starting a scan\n"
2191 "\"abort\" for aborting the current scan (returns true when abort was successful)\n"
2192 "\"status\" for progress report (in %) of the current scan"
2193};
2194
2195static const auto scan_objects_arg_desc = RPCArg{
2196 "scanobjects", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "Array of scan objects. Required for \"start\" action\n"
2197 "Every scan object is either a string descriptor or an object:",
2198 {
2199 {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "An output descriptor"},
2200 {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "An object with output descriptor and metadata",
2201 {
2202 {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "An output descriptor"},
2203 {"range", RPCArg::Type::RANGE, RPCArg::Default{1000}, "The range of HD chain indexes to explore (either end or [begin,end])"},
2204 }},
2205 },
2206 RPCArgOptions{.oneline_description="[scanobjects,...]"},
2207};
2208
2209static const auto scan_result_abort = RPCResult{
2210 "when action=='abort'", RPCResult::Type::BOOL, "success",
2211 "True if scan will be aborted (not necessarily before this RPC returns), or false if there is no scan to abort"
2212};
2214 "when action=='status' and no scan is in progress - possibly already completed", RPCResult::Type::NONE, "", ""
2215};
2217 "when action=='status' and a scan is currently in progress", RPCResult::Type::OBJ, "", "",
2218 {{RPCResult::Type::NUM, "progress", "Approximate percent complete"},}
2219};
2220
2221
2223{
2224 // raw() descriptor corresponding to mainnet address 12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S
2225 const std::string EXAMPLE_DESCRIPTOR_RAW = "raw(76a91411b366edfc0a8b66feebae5c2e25a7b6a5d1cf3188ac)#fm24fxxy";
2226
2227 return RPCHelpMan{
2228 "scantxoutset",
2229 "Scans the unspent transaction output set for entries that match certain output descriptors.\n"
2230 "Examples of output descriptors are:\n"
2231 " addr(<address>) Outputs whose output script corresponds to the specified address (does not include P2PK)\n"
2232 " raw(<hex script>) Outputs whose output script equals the specified hex-encoded bytes\n"
2233 " combo(<pubkey>) P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH outputs for the given pubkey\n"
2234 " pkh(<pubkey>) P2PKH outputs for the given pubkey\n"
2235 " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n"
2236 " tr(<pubkey>) P2TR\n"
2237 " tr(<pubkey>,{pk(<pubkey>)}) P2TR with single fallback pubkey in tapscript\n"
2238 " rawtr(<pubkey>) P2TR with the specified key as output key rather than inner\n"
2239 " wsh(and_v(v:pk(<pubkey>),after(2))) P2WSH miniscript with mandatory pubkey and a timelock\n"
2240 "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n"
2241 "or more path elements separated by \"/\", and optionally ending in \"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n"
2242 "unhardened or hardened child keys.\n"
2243 "In the latter case, a range needs to be specified by below if different from 1000.\n"
2244 "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n",
2245 {
2248 },
2249 {
2250 RPCResult{"when action=='start'; only returns after scan completes", RPCResult::Type::OBJ, "", "", {
2251 {RPCResult::Type::BOOL, "success", "Whether the scan was completed"},
2252 {RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs scanned"},
2253 {RPCResult::Type::NUM, "height", "The block height at which the scan was done"},
2254 {RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
2255 {RPCResult::Type::ARR, "unspents", "",
2256 {
2257 {RPCResult::Type::OBJ, "", "",
2258 {
2259 {RPCResult::Type::STR_HEX, "txid", "The transaction id"},
2260 {RPCResult::Type::NUM, "vout", "The vout value"},
2261 {RPCResult::Type::STR_HEX, "scriptPubKey", "The output script"},
2262 {RPCResult::Type::STR, "desc", "A specialized descriptor for the matched output script"},
2263 {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the unspent output"},
2264 {RPCResult::Type::BOOL, "coinbase", "Whether this is a coinbase output"},
2265 {RPCResult::Type::NUM, "height", "Height of the unspent transaction output"},
2266 {RPCResult::Type::STR_HEX, "blockhash", "Blockhash of the unspent transaction output"},
2267 {RPCResult::Type::NUM, "confirmations", "Number of confirmations of the unspent transaction output when the scan was done"},
2268 }},
2269 }},
2270 {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of all found unspent outputs in " + CURRENCY_UNIT},
2271 }},
2275 },
2277 HelpExampleCli("scantxoutset", "start \'[\"" + EXAMPLE_DESCRIPTOR_RAW + "\"]\'") +
2278 HelpExampleCli("scantxoutset", "status") +
2279 HelpExampleCli("scantxoutset", "abort") +
2280 HelpExampleRpc("scantxoutset", "\"start\", [\"" + EXAMPLE_DESCRIPTOR_RAW + "\"]") +
2281 HelpExampleRpc("scantxoutset", "\"status\"") +
2282 HelpExampleRpc("scantxoutset", "\"abort\"")
2283 },
2284 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2285{
2286 UniValue result(UniValue::VOBJ);
2287 const auto action{self.Arg<std::string>("action")};
2288 if (action == "status") {
2289 CoinsViewScanReserver reserver;
2290 if (reserver.reserve()) {
2291 // no scan in progress
2292 return UniValue::VNULL;
2293 }
2294 result.pushKV("progress", g_scan_progress.load());
2295 return result;
2296 } else if (action == "abort") {
2297 CoinsViewScanReserver reserver;
2298 if (reserver.reserve()) {
2299 // reserve was possible which means no scan was running
2300 return false;
2301 }
2302 // set the abort flag
2303 g_should_abort_scan = true;
2304 return true;
2305 } else if (action == "start") {
2306 CoinsViewScanReserver reserver;
2307 if (!reserver.reserve()) {
2308 throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
2309 }
2310
2311 if (request.params.size() < 2) {
2312 throw JSONRPCError(RPC_MISC_ERROR, "scanobjects argument is required for the start action");
2313 }
2314
2315 std::set<CScript> needles;
2316 std::map<CScript, std::string> descriptors;
2317 CAmount total_in = 0;
2318
2319 // loop through the scan objects
2320 for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
2321 FlatSigningProvider provider;
2322 auto scripts = EvalDescriptorStringOrObject(scanobject, provider);
2323 for (CScript& script : scripts) {
2324 std::string inferred = InferDescriptor(script, provider)->ToString();
2325 needles.emplace(script);
2326 descriptors.emplace(std::move(script), std::move(inferred));
2327 }
2328 }
2329
2330 // Scan the unspent transaction output set for inputs
2331 UniValue unspents(UniValue::VARR);
2332 std::vector<CTxOut> input_txos;
2333 std::map<COutPoint, Coin> coins;
2334 g_should_abort_scan = false;
2335 int64_t count = 0;
2336 std::unique_ptr<CCoinsViewCursor> pcursor;
2337 const CBlockIndex* tip;
2338 NodeContext& node = EnsureAnyNodeContext(request.context);
2339 {
2341 LOCK(cs_main);
2342 Chainstate& active_chainstate = chainman.ActiveChainstate();
2343 active_chainstate.ForceFlushStateToDisk();
2344 pcursor = CHECK_NONFATAL(active_chainstate.CoinsDB().Cursor());
2345 tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip());
2346 }
2347 bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins, node.rpc_interruption_point);
2348 result.pushKV("success", res);
2349 result.pushKV("txouts", count);
2350 result.pushKV("height", tip->nHeight);
2351 result.pushKV("bestblock", tip->GetBlockHash().GetHex());
2352
2353 for (const auto& it : coins) {
2354 const COutPoint& outpoint = it.first;
2355 const Coin& coin = it.second;
2356 const CTxOut& txo = coin.out;
2357 const CBlockIndex& coinb_block{*CHECK_NONFATAL(tip->GetAncestor(coin.nHeight))};
2358 input_txos.push_back(txo);
2359 total_in += txo.nValue;
2360
2361 UniValue unspent(UniValue::VOBJ);
2362 unspent.pushKV("txid", outpoint.hash.GetHex());
2363 unspent.pushKV("vout", outpoint.n);
2364 unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
2365 unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
2366 unspent.pushKV("amount", ValueFromAmount(txo.nValue));
2367 unspent.pushKV("coinbase", coin.IsCoinBase());
2368 unspent.pushKV("height", coin.nHeight);
2369 unspent.pushKV("blockhash", coinb_block.GetBlockHash().GetHex());
2370 unspent.pushKV("confirmations", tip->nHeight - coin.nHeight + 1);
2371
2372 unspents.push_back(std::move(unspent));
2373 }
2374 result.pushKV("unspents", std::move(unspents));
2375 result.pushKV("total_amount", ValueFromAmount(total_in));
2376 } else {
2377 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid action '%s'", action));
2378 }
2379 return result;
2380},
2381 };
2382}
2383
2385static std::atomic<int> g_scanfilter_progress;
2386static std::atomic<int> g_scanfilter_progress_height;
2387static std::atomic<bool> g_scanfilter_in_progress;
2388static std::atomic<bool> g_scanfilter_should_abort_scan;
2390{
2391private:
2392 bool m_could_reserve{false};
2393public:
2394 explicit BlockFiltersScanReserver() = default;
2395
2396 bool reserve() {
2398 if (g_scanfilter_in_progress.exchange(true)) {
2399 return false;
2400 }
2401 m_could_reserve = true;
2402 return true;
2403 }
2404
2406 if (m_could_reserve) {
2408 }
2409 }
2410};
2411
2412static bool CheckBlockFilterMatches(BlockManager& blockman, const CBlockIndex& blockindex, const GCSFilter::ElementSet& needles)
2413{
2414 const CBlock block{GetBlockChecked(blockman, blockindex)};
2415 const CBlockUndo block_undo{GetUndoChecked(blockman, blockindex)};
2416
2417 // Check if any of the outputs match the scriptPubKey
2418 for (const auto& tx : block.vtx) {
2419 if (std::any_of(tx->vout.cbegin(), tx->vout.cend(), [&](const auto& txout) {
2420 return needles.count(std::vector<unsigned char>(txout.scriptPubKey.begin(), txout.scriptPubKey.end())) != 0;
2421 })) {
2422 return true;
2423 }
2424 }
2425 // Check if any of the inputs match the scriptPubKey
2426 for (const auto& txundo : block_undo.vtxundo) {
2427 if (std::any_of(txundo.vprevout.cbegin(), txundo.vprevout.cend(), [&](const auto& coin) {
2428 return needles.count(std::vector<unsigned char>(coin.out.scriptPubKey.begin(), coin.out.scriptPubKey.end())) != 0;
2429 })) {
2430 return true;
2431 }
2432 }
2433
2434 return false;
2435}
2436
2438{
2439 return RPCHelpMan{
2440 "scanblocks",
2441 "Return relevant blockhashes for given descriptors (requires blockfilterindex).\n"
2442 "This call may take several minutes. Make sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
2443 {
2446 RPCArg{"start_height", RPCArg::Type::NUM, RPCArg::Default{0}, "Height to start to scan from"},
2447 RPCArg{"stop_height", RPCArg::Type::NUM, RPCArg::DefaultHint{"chain tip"}, "Height to stop to scan"},
2448 RPCArg{"filtertype", RPCArg::Type::STR, RPCArg::Default{BlockFilterTypeName(BlockFilterType::BASIC)}, "The type name of the filter"},
2450 {
2451 {"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"},
2452 },
2454 },
2455 {
2457 RPCResult{"When action=='start'; only returns after scan completes", RPCResult::Type::OBJ, "", "", {
2458 {RPCResult::Type::NUM, "from_height", "The height we started the scan from"},
2459 {RPCResult::Type::NUM, "to_height", "The height we ended the scan at"},
2460 {RPCResult::Type::ARR, "relevant_blocks", "Blocks that may have matched a scanobject.", {
2461 {RPCResult::Type::STR_HEX, "blockhash", "A relevant blockhash"},
2462 }},
2463 {RPCResult::Type::BOOL, "completed", "true if the scan process was not aborted"}
2464 }},
2465 RPCResult{"when action=='status' and a scan is currently in progress", RPCResult::Type::OBJ, "", "", {
2466 {RPCResult::Type::NUM, "progress", "Approximate percent complete"},
2467 {RPCResult::Type::NUM, "current_height", "Height of the block currently being scanned"},
2468 },
2469 },
2471 },
2473 HelpExampleCli("scanblocks", "start '[\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"]' 300000") +
2474 HelpExampleCli("scanblocks", "start '[\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"]' 100 150 basic") +
2475 HelpExampleCli("scanblocks", "status") +
2476 HelpExampleRpc("scanblocks", "\"start\", [\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"], 300000") +
2477 HelpExampleRpc("scanblocks", "\"start\", [\"addr(bcrt1q4u4nsgk6ug0sqz7r3rj9tykjxrsl0yy4d0wwte)\"], 100, 150, \"basic\"") +
2478 HelpExampleRpc("scanblocks", "\"status\"")
2479 },
2480 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2481{
2483 if (request.params[0].get_str() == "status") {
2484 BlockFiltersScanReserver reserver;
2485 if (reserver.reserve()) {
2486 // no scan in progress
2487 return NullUniValue;
2488 }
2489 ret.pushKV("progress", g_scanfilter_progress.load());
2490 ret.pushKV("current_height", g_scanfilter_progress_height.load());
2491 return ret;
2492 } else if (request.params[0].get_str() == "abort") {
2493 BlockFiltersScanReserver reserver;
2494 if (reserver.reserve()) {
2495 // reserve was possible which means no scan was running
2496 return false;
2497 }
2498 // set the abort flag
2500 return true;
2501 } else if (request.params[0].get_str() == "start") {
2502 BlockFiltersScanReserver reserver;
2503 if (!reserver.reserve()) {
2504 throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\"");
2505 }
2506 const std::string filtertype_name{request.params[4].isNull() ? "basic" : request.params[4].get_str()};
2507
2508 BlockFilterType filtertype;
2509 if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2510 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown filtertype");
2511 }
2512
2513 UniValue options{request.params[5].isNull() ? UniValue::VOBJ : request.params[5]};
2514 bool filter_false_positives{options.exists("filter_false_positives") ? options["filter_false_positives"].get_bool() : false};
2515
2516 BlockFilterIndex* index = GetBlockFilterIndex(filtertype);
2517 if (!index) {
2518 throw JSONRPCError(RPC_MISC_ERROR, "Index is not enabled for filtertype " + filtertype_name);
2519 }
2520
2521 NodeContext& node = EnsureAnyNodeContext(request.context);
2523
2524 // set the start-height
2525 const CBlockIndex* start_index = nullptr;
2526 const CBlockIndex* stop_block = nullptr;
2527 {
2528 LOCK(cs_main);
2529 CChain& active_chain = chainman.ActiveChain();
2530 start_index = active_chain.Genesis();
2531 stop_block = active_chain.Tip(); // If no stop block is provided, stop at the chain tip.
2532 if (!request.params[2].isNull()) {
2533 start_index = active_chain[request.params[2].getInt<int>()];
2534 if (!start_index) {
2535 throw JSONRPCError(RPC_MISC_ERROR, "Invalid start_height");
2536 }
2537 }
2538 if (!request.params[3].isNull()) {
2539 stop_block = active_chain[request.params[3].getInt<int>()];
2540 if (!stop_block || stop_block->nHeight < start_index->nHeight) {
2541 throw JSONRPCError(RPC_MISC_ERROR, "Invalid stop_height");
2542 }
2543 }
2544 }
2545 CHECK_NONFATAL(start_index);
2546 CHECK_NONFATAL(stop_block);
2547
2548 // loop through the scan objects, add scripts to the needle_set
2549 GCSFilter::ElementSet needle_set;
2550 for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
2551 FlatSigningProvider provider;
2552 std::vector<CScript> scripts = EvalDescriptorStringOrObject(scanobject, provider);
2553 for (const CScript& script : scripts) {
2554 needle_set.emplace(script.begin(), script.end());
2555 }
2556 }
2557 UniValue blocks(UniValue::VARR);
2558 const int amount_per_chunk = 10000;
2559 std::vector<BlockFilter> filters;
2560 int start_block_height = start_index->nHeight; // for progress reporting
2561 const int total_blocks_to_process = stop_block->nHeight - start_block_height;
2562
2565 g_scanfilter_progress_height = start_block_height;
2566 bool completed = true;
2567
2568 const CBlockIndex* end_range = nullptr;
2569 do {
2570 node.rpc_interruption_point(); // allow a clean shutdown
2572 completed = false;
2573 break;
2574 }
2575
2576 // split the lookup range in chunks if we are deeper than 'amount_per_chunk' blocks from the stopping block
2577 int start_block = !end_range ? start_index->nHeight : start_index->nHeight + 1; // to not include the previous round 'end_range' block
2578 end_range = (start_block + amount_per_chunk < stop_block->nHeight) ?
2579 WITH_LOCK(::cs_main, return chainman.ActiveChain()[start_block + amount_per_chunk]) :
2580 stop_block;
2581
2582 if (index->LookupFilterRange(start_block, end_range, filters)) {
2583 for (const BlockFilter& filter : filters) {
2584 // compare the elements-set with each filter
2585 if (filter.GetFilter().MatchAny(needle_set)) {
2586 if (filter_false_positives) {
2587 // Double check the filter matches by scanning the block
2588 const CBlockIndex& blockindex = *CHECK_NONFATAL(WITH_LOCK(cs_main, return chainman.m_blockman.LookupBlockIndex(filter.GetBlockHash())));
2589
2590 if (!CheckBlockFilterMatches(chainman.m_blockman, blockindex, needle_set)) {
2591 continue;
2592 }
2593 }
2594
2595 blocks.push_back(filter.GetBlockHash().GetHex());
2596 }
2597 }
2598 }
2599 start_index = end_range;
2600
2601 // update progress
2602 int blocks_processed = end_range->nHeight - start_block_height;
2603 if (total_blocks_to_process > 0) { // avoid division by zero
2604 g_scanfilter_progress = (int)(100.0 / total_blocks_to_process * blocks_processed);
2605 } else {
2607 }
2609
2610 // Finish if we reached the stop block
2611 } while (start_index != stop_block);
2612
2613 ret.pushKV("from_height", start_block_height);
2614 ret.pushKV("to_height", start_index->nHeight); // start_index is always the last scanned block here
2615 ret.pushKV("relevant_blocks", std::move(blocks));
2616 ret.pushKV("completed", completed);
2617 }
2618 else {
2619 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid action '%s'", request.params[0].get_str()));
2620 }
2621 return ret;
2622},
2623 };
2624}
2625
2627{
2628 return RPCHelpMan{
2629 "getdescriptoractivity",
2630 "Get spend and receive activity associated with a set of descriptors for a set of blocks. "
2631 "This command pairs well with the `relevant_blocks` output of `scanblocks()`.\n"
2632 "This call may take several minutes. If you encounter timeouts, try specifying no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
2633 {
2634 RPCArg{"blockhashes", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "The list of blockhashes to examine for activity. Order doesn't matter. Must be along main chain or an error is thrown.\n", {
2635 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A valid blockhash"},
2636 }},
2638 {"include_mempool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to include unconfirmed activity"},
2639 },
2640 RPCResult{
2641 RPCResult::Type::OBJ, "", "", {
2642 {RPCResult::Type::ARR, "activity", "events", {
2643 {RPCResult::Type::OBJ, "", "", {
2644 {RPCResult::Type::STR, "type", "always 'spend'"},
2645 {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the spent output"},
2646 {RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "The blockhash this spend appears in (omitted if unconfirmed)"},
2647 {RPCResult::Type::NUM, "height", /*optional=*/true, "Height of the spend (omitted if unconfirmed)"},
2648 {RPCResult::Type::STR_HEX, "spend_txid", "The txid of the spending transaction"},
2649 {RPCResult::Type::NUM, "spend_vout", "The vout of the spend"},
2650 {RPCResult::Type::STR_HEX, "prevout_txid", "The txid of the prevout"},
2651 {RPCResult::Type::NUM, "prevout_vout", "The vout of the prevout"},
2652 {RPCResult::Type::OBJ, "prevout_spk", "", ScriptPubKeyDoc()},
2653 }},
2654 {RPCResult::Type::OBJ, "", "", {
2655 {RPCResult::Type::STR, "type", "always 'receive'"},
2656 {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the new output"},
2657 {RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "The block that this receive is in (omitted if unconfirmed)"},
2658 {RPCResult::Type::NUM, "height", /*optional=*/true, "The height of the receive (omitted if unconfirmed)"},
2659 {RPCResult::Type::STR_HEX, "txid", "The txid of the receiving transaction"},
2660 {RPCResult::Type::NUM, "vout", "The vout of the receiving output"},
2661 {RPCResult::Type::OBJ, "output_spk", "", ScriptPubKeyDoc()},
2662 }},
2663 // TODO is the skip_type_check avoidable with a heterogeneous ARR?
2664 }, /*skip_type_check=*/true},
2665 },
2666 },
2668 HelpExampleCli("getdescriptoractivity", "'[\"000000000000000000001347062c12fded7c528943c8ce133987e2e2f5a840ee\"]' '[\"addr(bc1qzl6nsgqzu89a66l50cvwapnkw5shh23zarqkw9)\"]'")
2669 },
2670 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2671{
2673 UniValue activity(UniValue::VARR);
2674 NodeContext& node = EnsureAnyNodeContext(request.context);
2676
2677 struct CompareByHeightAscending {
2678 bool operator()(const CBlockIndex* a, const CBlockIndex* b) const {
2679 return a->nHeight < b->nHeight;
2680 }
2681 };
2682
2683 std::set<const CBlockIndex*, CompareByHeightAscending> blockindexes_sorted;
2684
2685 {
2686 // Validate all given blockhashes, and ensure blocks are along a single chain.
2687 LOCK(::cs_main);
2688 for (const UniValue& blockhash : request.params[0].get_array().getValues()) {
2689 uint256 bhash = ParseHashV(blockhash, "blockhash");
2690 CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(bhash);
2691 if (!pindex) {
2692 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
2693 }
2694 if (!chainman.ActiveChain().Contains(pindex)) {
2695 throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain");
2696 }
2697 blockindexes_sorted.insert(pindex);
2698 }
2699 }
2700
2701 std::set<CScript> scripts_to_watch;
2702
2703 // Determine scripts to watch.
2704 for (const UniValue& scanobject : request.params[1].get_array().getValues()) {
2705 FlatSigningProvider provider;
2706 std::vector<CScript> scripts = EvalDescriptorStringOrObject(scanobject, provider);
2707
2708 for (const CScript& script : scripts) {
2709 scripts_to_watch.insert(script);
2710 }
2711 }
2712
2713 const auto AddSpend = [&](
2714 const CScript& spk,
2715 const CAmount val,
2716 const CTransactionRef& tx,
2717 int vin,
2718 const CTxIn& txin,
2719 const CBlockIndex* index
2720 ) {
2721 UniValue event(UniValue::VOBJ);
2722 UniValue spkUv(UniValue::VOBJ);
2723 ScriptToUniv(spk, /*out=*/spkUv, /*include_hex=*/true, /*include_address=*/true);
2724
2725 event.pushKV("type", "spend");
2726 event.pushKV("amount", ValueFromAmount(val));
2727 if (index) {
2728 event.pushKV("blockhash", index->GetBlockHash().ToString());
2729 event.pushKV("height", index->nHeight);
2730 }
2731 event.pushKV("spend_txid", tx->GetHash().ToString());
2732 event.pushKV("spend_vin", vin);
2733 event.pushKV("prevout_txid", txin.prevout.hash.ToString());
2734 event.pushKV("prevout_vout", txin.prevout.n);
2735 event.pushKV("prevout_spk", spkUv);
2736
2737 return event;
2738 };
2739
2740 const auto AddReceive = [&](const CTxOut& txout, const CBlockIndex* index, int vout, const CTransactionRef& tx) {
2741 UniValue event(UniValue::VOBJ);
2742 UniValue spkUv(UniValue::VOBJ);
2743 ScriptToUniv(txout.scriptPubKey, /*out=*/spkUv, /*include_hex=*/true, /*include_address=*/true);
2744
2745 event.pushKV("type", "receive");
2746 event.pushKV("amount", ValueFromAmount(txout.nValue));
2747 if (index) {
2748 event.pushKV("blockhash", index->GetBlockHash().ToString());
2749 event.pushKV("height", index->nHeight);
2750 }
2751 event.pushKV("txid", tx->GetHash().ToString());
2752 event.pushKV("vout", vout);
2753 event.pushKV("output_spk", spkUv);
2754
2755 return event;
2756 };
2757
2758 BlockManager* blockman;
2759 Chainstate& active_chainstate = chainman.ActiveChainstate();
2760 {
2761 LOCK(::cs_main);
2762 blockman = CHECK_NONFATAL(&active_chainstate.m_blockman);
2763 }
2764
2765 for (const CBlockIndex* blockindex : blockindexes_sorted) {
2766 const CBlock block{GetBlockChecked(chainman.m_blockman, *blockindex)};
2767 const CBlockUndo block_undo{GetUndoChecked(*blockman, *blockindex)};
2768
2769 for (size_t i = 0; i < block.vtx.size(); ++i) {
2770 const auto& tx = block.vtx.at(i);
2771
2772 if (!tx->IsCoinBase()) {
2773 // skip coinbase; spends can't happen there.
2774 const auto& txundo = block_undo.vtxundo.at(i - 1);
2775
2776 for (size_t vin_idx = 0; vin_idx < tx->vin.size(); ++vin_idx) {
2777 const auto& coin = txundo.vprevout.at(vin_idx);
2778 const auto& txin = tx->vin.at(vin_idx);
2779 if (scripts_to_watch.contains(coin.out.scriptPubKey)) {
2780 activity.push_back(AddSpend(
2781 coin.out.scriptPubKey, coin.out.nValue, tx, vin_idx, txin, blockindex));
2782 }
2783 }
2784 }
2785
2786 for (size_t vout_idx = 0; vout_idx < tx->vout.size(); ++vout_idx) {
2787 const auto& vout = tx->vout.at(vout_idx);
2788 if (scripts_to_watch.contains(vout.scriptPubKey)) {
2789 activity.push_back(AddReceive(vout, blockindex, vout_idx, tx));
2790 }
2791 }
2792 }
2793 }
2794
2795 bool search_mempool = true;
2796 if (!request.params[2].isNull()) {
2797 search_mempool = request.params[2].get_bool();
2798 }
2799
2800 if (search_mempool) {
2801 const CTxMemPool& mempool = EnsureMemPool(node);
2802 LOCK(::cs_main);
2803 LOCK(mempool.cs);
2804 const CCoinsViewCache& coins_view = &active_chainstate.CoinsTip();
2805
2806 for (const CTxMemPoolEntry& e : mempool.entryAll()) {
2807 const auto& tx = e.GetSharedTx();
2808
2809 for (size_t vin_idx = 0; vin_idx < tx->vin.size(); ++vin_idx) {
2810 CScript scriptPubKey;
2811 CAmount value;
2812 const auto& txin = tx->vin.at(vin_idx);
2813 std::optional<Coin> coin = coins_view.GetCoin(txin.prevout);
2814
2815 // Check if the previous output is in the chain
2816 if (!coin) {
2817 // If not found in the chain, check the mempool. Likely, this is a
2818 // child transaction of another transaction in the mempool.
2819 CTransactionRef prev_tx = CHECK_NONFATAL(mempool.get(txin.prevout.hash));
2820
2821 if (txin.prevout.n >= prev_tx->vout.size()) {
2822 throw std::runtime_error("Invalid output index");
2823 }
2824 const CTxOut& out = prev_tx->vout[txin.prevout.n];
2825 scriptPubKey = out.scriptPubKey;
2826 value = out.nValue;
2827 } else {
2828 // Coin found in the chain
2829 const CTxOut& out = coin->out;
2830 scriptPubKey = out.scriptPubKey;
2831 value = out.nValue;
2832 }
2833
2834 if (scripts_to_watch.contains(scriptPubKey)) {
2835 UniValue event(UniValue::VOBJ);
2836 activity.push_back(AddSpend(
2837 scriptPubKey, value, tx, vin_idx, txin, nullptr));
2838 }
2839 }
2840
2841 for (size_t vout_idx = 0; vout_idx < tx->vout.size(); ++vout_idx) {
2842 const auto& vout = tx->vout.at(vout_idx);
2843 if (scripts_to_watch.contains(vout.scriptPubKey)) {
2844 activity.push_back(AddReceive(vout, nullptr, vout_idx, tx));
2845 }
2846 }
2847 }
2848 }
2849
2850 ret.pushKV("activity", activity);
2851 return ret;
2852},
2853 };
2854}
2855
2857{
2858 return RPCHelpMan{
2859 "getblockfilter",
2860 "Retrieve a BIP 157 content filter for a particular block.\n",
2861 {
2862 {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hash of the block"},
2863 {"filtertype", RPCArg::Type::STR, RPCArg::Default{BlockFilterTypeName(BlockFilterType::BASIC)}, "The type name of the filter"},
2864 },
2865 RPCResult{
2866 RPCResult::Type::OBJ, "", "",
2867 {
2868 {RPCResult::Type::STR_HEX, "filter", "the hex-encoded filter data"},
2869 {RPCResult::Type::STR_HEX, "header", "the hex-encoded filter header"},
2870 }},
2872 HelpExampleCli("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" \"basic\"") +
2873 HelpExampleRpc("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\", \"basic\"")
2874 },
2875 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2876{
2877 uint256 block_hash = ParseHashV(request.params[0], "blockhash");
2878 std::string filtertype_name = BlockFilterTypeName(BlockFilterType::BASIC);
2879 if (!request.params[1].isNull()) {
2880 filtertype_name = request.params[1].get_str();
2881 }
2882
2883 BlockFilterType filtertype;
2884 if (!BlockFilterTypeByName(filtertype_name, filtertype)) {
2885 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown filtertype");
2886 }
2887
2888 BlockFilterIndex* index = GetBlockFilterIndex(filtertype);
2889 if (!index) {
2890 throw JSONRPCError(RPC_MISC_ERROR, "Index is not enabled for filtertype " + filtertype_name);
2891 }
2892
2893 const CBlockIndex* block_index;
2894 bool block_was_connected;
2895 {
2896 ChainstateManager& chainman = EnsureAnyChainman(request.context);
2897 LOCK(cs_main);
2898 block_index = chainman.m_blockman.LookupBlockIndex(block_hash);
2899 if (!block_index) {
2900 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
2901 }
2902 block_was_connected = block_index->IsValid(BLOCK_VALID_SCRIPTS);
2903 }
2904
2905 bool index_ready = index->BlockUntilSyncedToCurrentChain();
2906
2907 BlockFilter filter;
2908 uint256 filter_header;
2909 if (!index->LookupFilter(block_index, filter) ||
2910 !index->LookupFilterHeader(block_index, filter_header)) {
2911 int err_code;
2912 std::string errmsg = "Filter not found.";
2913
2914 if (!block_was_connected) {
2915 err_code = RPC_INVALID_ADDRESS_OR_KEY;
2916 errmsg += " Block was not connected to active chain.";
2917 } else if (!index_ready) {
2918 err_code = RPC_MISC_ERROR;
2919 errmsg += " Block filters are still in the process of being indexed.";
2920 } else {
2921 err_code = RPC_INTERNAL_ERROR;
2922 errmsg += " This error is unexpected and indicates index corruption.";
2923 }
2924
2925 throw JSONRPCError(err_code, errmsg);
2926 }
2927
2929 ret.pushKV("filter", HexStr(filter.GetEncodedFilter()));
2930 ret.pushKV("header", filter_header.GetHex());
2931 return ret;
2932},
2933 };
2934}
2935
2941{
2943public:
2944 NetworkDisable(CConnman& connman) : m_connman(connman) {
2947 throw JSONRPCError(RPC_MISC_ERROR, "Network activity could not be suspended.");
2948 }
2949 };
2952 };
2953};
2954
2960{
2963public:
2964 TemporaryRollback(ChainstateManager& chainman, const CBlockIndex& index) : m_chainman(chainman), m_invalidate_index(index) {
2966 };
2969 };
2970};
2971
2978{
2979 return RPCHelpMan{
2980 "dumptxoutset",
2981 "Write the serialized UTXO set to a file. This can be used in loadtxoutset afterwards if this snapshot height is supported in the chainparams as well.\n\n"
2982 "Unless the \"latest\" type is requested, the node will roll back to the requested height and network activity will be suspended during this process. "
2983 "Because of this it is discouraged to interact with the node in any other way during the execution of this call to avoid inconsistent results and race conditions, particularly RPCs that interact with blockstorage.\n\n"
2984 "This call may take several minutes. Make sure to use no RPC timeout (bitcoin-cli -rpcclienttimeout=0)",
2985 {
2986 {"path", RPCArg::Type::STR, RPCArg::Optional::NO, "Path to the output file. If relative, will be prefixed by datadir."},
2987 {"type", RPCArg::Type::STR, RPCArg::Default(""), "The type of snapshot to create. Can be \"latest\" to create a snapshot of the current UTXO set or \"rollback\" to temporarily roll back the state of the node to a historical block before creating the snapshot of a historical UTXO set. This parameter can be omitted if a separate \"rollback\" named parameter is specified indicating the height or hash of a specific historical block. If \"rollback\" is specified and separate \"rollback\" named parameter is not specified, this will roll back to the latest valid snapshot block that can currently be loaded with loadtxoutset."},
2989 {
2991 "Height or hash of the block to roll back to before creating the snapshot. Note: The further this number is from the tip, the longer this process will take. Consider setting a higher -rpcclienttimeout value in this case.",
2992 RPCArgOptions{.skip_type_check = true, .type_str = {"", "string or numeric"}}},
2993 },
2994 },
2995 },
2996 RPCResult{
2997 RPCResult::Type::OBJ, "", "",
2998 {
2999 {RPCResult::Type::NUM, "coins_written", "the number of coins written in the snapshot"},
3000 {RPCResult::Type::STR_HEX, "base_hash", "the hash of the base of the snapshot"},
3001 {RPCResult::Type::NUM, "base_height", "the height of the base of the snapshot"},
3002 {RPCResult::Type::STR, "path", "the absolute path that the snapshot was written to"},
3003 {RPCResult::Type::STR_HEX, "txoutset_hash", "the hash of the UTXO set contents"},
3004 {RPCResult::Type::NUM, "nchaintx", "the number of transactions in the chain up to and including the base block"},
3005 }
3006 },
3008 HelpExampleCli("-rpcclienttimeout=0 dumptxoutset", "utxo.dat latest") +
3009 HelpExampleCli("-rpcclienttimeout=0 dumptxoutset", "utxo.dat rollback") +
3010 HelpExampleCli("-rpcclienttimeout=0 -named dumptxoutset", R"(utxo.dat rollback=853456)")
3011 },
3012 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
3013{
3014 NodeContext& node = EnsureAnyNodeContext(request.context);
3015 const CBlockIndex* tip{WITH_LOCK(::cs_main, return node.chainman->ActiveChain().Tip())};
3016 const CBlockIndex* target_index{nullptr};
3017 const std::string snapshot_type{self.Arg<std::string>("type")};
3018 const UniValue options{request.params[2].isNull() ? UniValue::VOBJ : request.params[2]};
3019 if (options.exists("rollback")) {
3020 if (!snapshot_type.empty() && snapshot_type != "rollback") {
3021 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid snapshot type \"%s\" specified with rollback option", snapshot_type));
3022 }
3023 target_index = ParseHashOrHeight(options["rollback"], *node.chainman);
3024 } else if (snapshot_type == "rollback") {
3025 auto snapshot_heights = node.chainman->GetParams().GetAvailableSnapshotHeights();
3026 CHECK_NONFATAL(snapshot_heights.size() > 0);
3027 auto max_height = std::max_element(snapshot_heights.begin(), snapshot_heights.end());
3028 target_index = ParseHashOrHeight(*max_height, *node.chainman);
3029 } else if (snapshot_type == "latest") {
3030 target_index = tip;
3031 } else {
3032 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid snapshot type \"%s\" specified. Please specify \"rollback\" or \"latest\"", snapshot_type));
3033 }
3034
3035 const ArgsManager& args{EnsureAnyArgsman(request.context)};
3036 const fs::path path = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(request.params[0].get_str()));
3037 // Write to a temporary path and then move into `path` on completion
3038 // to avoid confusion due to an interruption.
3039 const fs::path temppath = fsbridge::AbsPathJoin(args.GetDataDirNet(), fs::u8path(request.params[0].get_str() + ".incomplete"));
3040
3041 if (fs::exists(path)) {
3042 throw JSONRPCError(
3044 path.utf8string() + " already exists. If you are sure this is what you want, "
3045 "move it out of the way first");
3046 }
3047
3048 FILE* file{fsbridge::fopen(temppath, "wb")};
3049 AutoFile afile{file};
3050 if (afile.IsNull()) {
3051 throw JSONRPCError(
3053 "Couldn't open file " + temppath.utf8string() + " for writing.");
3054 }
3055
3056 CConnman& connman = EnsureConnman(node);
3057 const CBlockIndex* invalidate_index{nullptr};
3058 std::optional<NetworkDisable> disable_network;
3059 std::optional<TemporaryRollback> temporary_rollback;
3060
3061 // If the user wants to dump the txoutset of the current tip, we don't have
3062 // to roll back at all
3063 if (target_index != tip) {
3064 // If the node is running in pruned mode we ensure all necessary block
3065 // data is available before starting to roll back.
3066 if (node.chainman->m_blockman.IsPruneMode()) {
3067 LOCK(node.chainman->GetMutex());
3068 const CBlockIndex* current_tip{node.chainman->ActiveChain().Tip()};
3069 const CBlockIndex* first_block{node.chainman->m_blockman.GetFirstBlock(*current_tip, /*status_mask=*/BLOCK_HAVE_MASK)};
3070 if (first_block->nHeight > target_index->nHeight) {
3071 throw JSONRPCError(RPC_MISC_ERROR, "Could not roll back to requested height since necessary block data is already pruned.");
3072 }
3073 }
3074
3075 // Suspend network activity for the duration of the process when we are
3076 // rolling back the chain to get a utxo set from a past height. We do
3077 // this so we don't punish peers that send us that send us data that
3078 // seems wrong in this temporary state. For example a normal new block
3079 // would be classified as a block connecting an invalid block.
3080 // Skip if the network is already disabled because this
3081 // automatically re-enables the network activity at the end of the
3082 // process which may not be what the user wants.
3083 if (connman.GetNetworkActive()) {
3084 disable_network.emplace(connman);
3085 }
3086
3087 invalidate_index = WITH_LOCK(::cs_main, return node.chainman->ActiveChain().Next(target_index));
3088 temporary_rollback.emplace(*node.chainman, *invalidate_index);
3089 }
3090
3091 Chainstate* chainstate;
3092 std::unique_ptr<CCoinsViewCursor> cursor;
3093 CCoinsStats stats;
3094 {
3095 // Lock the chainstate before calling PrepareUtxoSnapshot, to be able
3096 // to get a UTXO database cursor while the chain is pointing at the
3097 // target block. After that, release the lock while calling
3098 // WriteUTXOSnapshot. The cursor will remain valid and be used by
3099 // WriteUTXOSnapshot to write a consistent snapshot even if the
3100 // chainstate changes.
3101 LOCK(node.chainman->GetMutex());
3102 chainstate = &node.chainman->ActiveChainstate();
3103 // In case there is any issue with a block being read from disk we need
3104 // to stop here, otherwise the dump could still be created for the wrong
3105 // height.
3106 // The new tip could also not be the target block if we have a stale
3107 // sister block of invalidate_index. This block (or a descendant) would
3108 // be activated as the new tip and we would not get to new_tip_index.
3109 if (target_index != chainstate->m_chain.Tip()) {
3110 LogWarning("dumptxoutset failed to roll back to requested height, reverting to tip.\n");
3111 throw JSONRPCError(RPC_MISC_ERROR, "Could not roll back to requested height.");
3112 } else {
3113 std::tie(cursor, stats, tip) = PrepareUTXOSnapshot(*chainstate, node.rpc_interruption_point);
3114 }
3115 }
3116
3117 UniValue result = WriteUTXOSnapshot(*chainstate, cursor.get(), &stats, tip, afile, path, temppath, node.rpc_interruption_point);
3118 fs::rename(temppath, path);
3119
3120 result.pushKV("path", path.utf8string());
3121 return result;
3122},
3123 };
3124}
3125
3126std::tuple<std::unique_ptr<CCoinsViewCursor>, CCoinsStats, const CBlockIndex*>
3128 Chainstate& chainstate,
3129 const std::function<void()>& interruption_point)
3130{
3131 std::unique_ptr<CCoinsViewCursor> pcursor;
3132 std::optional<CCoinsStats> maybe_stats;
3133 const CBlockIndex* tip;
3134
3135 {
3136 // We need to lock cs_main to ensure that the coinsdb isn't written to
3137 // between (i) flushing coins cache to disk (coinsdb), (ii) getting stats
3138 // based upon the coinsdb, and (iii) constructing a cursor to the
3139 // coinsdb for use in WriteUTXOSnapshot.
3140 //
3141 // Cursors returned by leveldb iterate over snapshots, so the contents
3142 // of the pcursor will not be affected by simultaneous writes during
3143 // use below this block.
3144 //
3145 // See discussion here:
3146 // https://github.com/bitcoin/bitcoin/pull/15606#discussion_r274479369
3147 //
3149
3150 chainstate.ForceFlushStateToDisk();
3151
3152 maybe_stats = GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman, CoinStatsHashType::HASH_SERIALIZED, interruption_point);
3153 if (!maybe_stats) {
3154 throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
3155 }
3156
3157 pcursor = chainstate.CoinsDB().Cursor();
3158 tip = CHECK_NONFATAL(chainstate.m_blockman.LookupBlockIndex(maybe_stats->hashBlock));
3159 }
3160
3161 return {std::move(pcursor), *CHECK_NONFATAL(maybe_stats), tip};
3162}
3163
3165 Chainstate& chainstate,
3166 CCoinsViewCursor* pcursor,
3167 CCoinsStats* maybe_stats,
3168 const CBlockIndex* tip,
3169 AutoFile& afile,
3170 const fs::path& path,
3171 const fs::path& temppath,
3172 const std::function<void()>& interruption_point)
3173{
3174 LOG_TIME_SECONDS(strprintf("writing UTXO snapshot at height %s (%s) to file %s (via %s)",
3175 tip->nHeight, tip->GetBlockHash().ToString(),
3176 fs::PathToString(path), fs::PathToString(temppath)));
3177
3178 SnapshotMetadata metadata{chainstate.m_chainman.GetParams().MessageStart(), tip->GetBlockHash(), maybe_stats->coins_count};
3179
3180 afile << metadata;
3181
3182 COutPoint key;
3183 Txid last_hash;
3184 Coin coin;
3185 unsigned int iter{0};
3186 size_t written_coins_count{0};
3187 std::vector<std::pair<uint32_t, Coin>> coins;
3188
3189 // To reduce space the serialization format of the snapshot avoids
3190 // duplication of tx hashes. The code takes advantage of the guarantee by
3191 // leveldb that keys are lexicographically sorted.
3192 // In the coins vector we collect all coins that belong to a certain tx hash
3193 // (key.hash) and when we have them all (key.hash != last_hash) we write
3194 // them to file using the below lambda function.
3195 // See also https://github.com/bitcoin/bitcoin/issues/25675
3196 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) {
3197 afile << last_hash;
3198 WriteCompactSize(afile, coins.size());
3199 for (const auto& [n, coin] : coins) {
3200 WriteCompactSize(afile, n);
3201 afile << coin;
3202 ++written_coins_count;
3203 }
3204 };
3205
3206 pcursor->GetKey(key);
3207 last_hash = key.hash;
3208 while (pcursor->Valid()) {
3209 if (iter % 5000 == 0) interruption_point();
3210 ++iter;
3211 if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
3212 if (key.hash != last_hash) {
3213 write_coins_to_file(afile, last_hash, coins, written_coins_count);
3214 last_hash = key.hash;
3215 coins.clear();
3216 }
3217 coins.emplace_back(key.n, coin);
3218 }
3219 pcursor->Next();
3220 }
3221
3222 if (!coins.empty()) {
3223 write_coins_to_file(afile, last_hash, coins, written_coins_count);
3224 }
3225
3226 CHECK_NONFATAL(written_coins_count == maybe_stats->coins_count);
3227
3228 afile.fclose();
3229
3230 UniValue result(UniValue::VOBJ);
3231 result.pushKV("coins_written", written_coins_count);
3232 result.pushKV("base_hash", tip->GetBlockHash().ToString());
3233 result.pushKV("base_height", tip->nHeight);
3234 result.pushKV("path", path.utf8string());
3235 result.pushKV("txoutset_hash", maybe_stats->hashSerialized.ToString());
3236 result.pushKV("nchaintx", tip->m_chain_tx_count);
3237 return result;
3238}
3239
3242 Chainstate& chainstate,
3243 AutoFile& afile,
3244 const fs::path& path,
3245 const fs::path& tmppath)
3246{
3247 auto [cursor, stats, tip]{WITH_LOCK(::cs_main, return PrepareUTXOSnapshot(chainstate, node.rpc_interruption_point))};
3248 return WriteUTXOSnapshot(chainstate, cursor.get(), &stats, tip, afile, path, tmppath, node.rpc_interruption_point);
3249}
3250
3252{
3253 return RPCHelpMan{
3254 "loadtxoutset",
3255 "Load the serialized UTXO set from a file.\n"
3256 "Once this snapshot is loaded, its contents will be "
3257 "deserialized into a second chainstate data structure, which is then used to sync to "
3258 "the network's tip. "
3259 "Meanwhile, the original chainstate will complete the initial block download process in "
3260 "the background, eventually validating up to the block that the snapshot is based upon.\n\n"
3261
3262 "The result is a usable bitcoind instance that is current with the network tip in a "
3263 "matter of minutes rather than hours. UTXO snapshot are typically obtained from "
3264 "third-party sources (HTTP, torrent, etc.) which is reasonable since their "
3265 "contents are always checked by hash.\n\n"
3266
3267 "You can find more information on this process in the `assumeutxo` design "
3268 "document (<https://github.com/bitcoin/bitcoin/blob/master/doc/design/assumeutxo.md>).",
3269 {
3270 {"path",
3273 "path to the snapshot file. If relative, will be prefixed by datadir."},
3274 },
3275 RPCResult{
3276 RPCResult::Type::OBJ, "", "",
3277 {
3278 {RPCResult::Type::NUM, "coins_loaded", "the number of coins loaded from the snapshot"},
3279 {RPCResult::Type::STR_HEX, "tip_hash", "the hash of the base of the snapshot"},
3280 {RPCResult::Type::NUM, "base_height", "the height of the base of the snapshot"},
3281 {RPCResult::Type::STR, "path", "the absolute path that the snapshot was loaded from"},
3282 }
3283 },
3285 HelpExampleCli("-rpcclienttimeout=0 loadtxoutset", "utxo.dat")
3286 },
3287 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
3288{
3289 NodeContext& node = EnsureAnyNodeContext(request.context);
3291 const fs::path path{AbsPathForConfigVal(EnsureArgsman(node), fs::u8path(self.Arg<std::string>("path")))};
3292
3293 FILE* file{fsbridge::fopen(path, "rb")};
3294 AutoFile afile{file};
3295 if (afile.IsNull()) {
3296 throw JSONRPCError(
3298 "Couldn't open file " + path.utf8string() + " for reading.");
3299 }
3300
3301 SnapshotMetadata metadata{chainman.GetParams().MessageStart()};
3302 try {
3303 afile >> metadata;
3304 } catch (const std::ios_base::failure& e) {
3305 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("Unable to parse metadata: %s", e.what()));
3306 }
3307
3308 auto activation_result{chainman.ActivateSnapshot(afile, metadata, false)};
3309 if (!activation_result) {
3310 throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to load UTXO snapshot: %s. (%s)", util::ErrorString(activation_result).original, path.utf8string()));
3311 }
3312
3313 // Because we can't provide historical blocks during tip or background sync.
3314 // Update local services to reflect we are a limited peer until we are fully sync.
3315 node.connman->RemoveLocalServices(NODE_NETWORK);
3316 // Setting the limited state is usually redundant because the node can always
3317 // provide the last 288 blocks, but it doesn't hurt to set it.
3318 node.connman->AddLocalServices(NODE_NETWORK_LIMITED);
3319
3320 CBlockIndex& snapshot_index{*CHECK_NONFATAL(*activation_result)};
3321
3322 UniValue result(UniValue::VOBJ);
3323 result.pushKV("coins_loaded", metadata.m_coins_count);
3324 result.pushKV("tip_hash", snapshot_index.GetBlockHash().ToString());
3325 result.pushKV("base_height", snapshot_index.nHeight);
3326 result.pushKV("path", fs::PathToString(path));
3327 return result;
3328},
3329 };
3330}
3331
3332const std::vector<RPCResult> RPCHelpForChainstate{
3333 {RPCResult::Type::NUM, "blocks", "number of blocks in this chainstate"},
3334 {RPCResult::Type::STR_HEX, "bestblockhash", "blockhash of the tip"},
3335 {RPCResult::Type::STR_HEX, "bits", "nBits: compact representation of the block difficulty target"},
3336 {RPCResult::Type::STR_HEX, "target", "The difficulty target"},
3337 {RPCResult::Type::NUM, "difficulty", "difficulty of the tip"},
3338 {RPCResult::Type::NUM, "verificationprogress", "progress towards the network tip"},
3339 {RPCResult::Type::STR_HEX, "snapshot_blockhash", /*optional=*/true, "the base block of the snapshot this chainstate is based on, if any"},
3340 {RPCResult::Type::NUM, "coins_db_cache_bytes", "size of the coinsdb cache"},
3341 {RPCResult::Type::NUM, "coins_tip_cache_bytes", "size of the coinstip cache"},
3342 {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."},
3343};
3344
3346{
3347return RPCHelpMan{
3348 "getchainstates",
3349 "Return information about chainstates.\n",
3350 {},
3351 RPCResult{
3352 RPCResult::Type::OBJ, "", "", {
3353 {RPCResult::Type::NUM, "headers", "the number of headers seen so far"},
3354 {RPCResult::Type::ARR, "chainstates", "list of the chainstates ordered by work, with the most-work (active) chainstate last", {{RPCResult::Type::OBJ, "", "", RPCHelpForChainstate},}},
3355 }
3356 },
3358 HelpExampleCli("getchainstates", "")
3359 + HelpExampleRpc("getchainstates", "")
3360 },
3361 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
3362{
3363 LOCK(cs_main);
3365
3366 ChainstateManager& chainman = EnsureAnyChainman(request.context);
3367
3368 auto make_chain_data = [&](const Chainstate& cs, bool validated) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
3371 if (!cs.m_chain.Tip()) {
3372 return data;
3373 }
3374 const CChain& chain = cs.m_chain;
3375 const CBlockIndex* tip = chain.Tip();
3376
3377 data.pushKV("blocks", (int)chain.Height());
3378 data.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
3379 data.pushKV("bits", strprintf("%08x", tip->nBits));
3380 data.pushKV("target", GetTarget(*tip, chainman.GetConsensus().powLimit).GetHex());
3381 data.pushKV("difficulty", GetDifficulty(*tip));
3382 data.pushKV("verificationprogress", chainman.GuessVerificationProgress(tip));
3383 data.pushKV("coins_db_cache_bytes", cs.m_coinsdb_cache_size_bytes);
3384 data.pushKV("coins_tip_cache_bytes", cs.m_coinstip_cache_size_bytes);
3385 if (cs.m_from_snapshot_blockhash) {
3386 data.pushKV("snapshot_blockhash", cs.m_from_snapshot_blockhash->ToString());
3387 }
3388 data.pushKV("validated", validated);
3389 return data;
3390 };
3391
3392 obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1);
3393
3394 const auto& chainstates = chainman.GetAll();
3395 UniValue obj_chainstates{UniValue::VARR};
3396 for (Chainstate* cs : chainstates) {
3397 obj_chainstates.push_back(make_chain_data(*cs, !cs->m_from_snapshot_blockhash || chainstates.size() == 1));
3398 }
3399 obj.pushKV("chainstates", std::move(obj_chainstates));
3400 return obj;
3401}
3402 };
3403}
3404
3405
3407{
3408 static const CRPCCommand commands[]{
3409 {"blockchain", &getblockchaininfo},
3410 {"blockchain", &getchaintxstats},
3411 {"blockchain", &getblockstats},
3412 {"blockchain", &getbestblockhash},
3413 {"blockchain", &getblockcount},
3414 {"blockchain", &getblock},
3415 {"blockchain", &getblockfrompeer},
3416 {"blockchain", &getblockhash},
3417 {"blockchain", &getblockheader},
3418 {"blockchain", &getchaintips},
3419 {"blockchain", &getdifficulty},
3420 {"blockchain", &getdeploymentinfo},
3421 {"blockchain", &gettxout},
3422 {"blockchain", &gettxoutsetinfo},
3423 {"blockchain", &pruneblockchain},
3424 {"blockchain", &verifychain},
3425 {"blockchain", &preciousblock},
3426 {"blockchain", &scantxoutset},
3427 {"blockchain", &scanblocks},
3428 {"blockchain", &getdescriptoractivity},
3429 {"blockchain", &getblockfilter},
3430 {"blockchain", &dumptxoutset},
3431 {"blockchain", &loadtxoutset},
3432 {"blockchain", &getchainstates},
3433 {"hidden", &invalidateblock},
3434 {"hidden", &reconsiderblock},
3435 {"hidden", &waitfornewblock},
3436 {"hidden", &waitforblock},
3437 {"hidden", &waitforblockheight},
3439 };
3440 for (const auto& c : commands) {
3441 t.appendCommand(c.name, &c);
3442 }
3443}
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:226
int ret
ArgsManager & args
Definition: bitcoind.cpp:277
static RPCHelpMan getblock()
Definition: blockchain.cpp:725
static RPCHelpMan getdifficulty()
Definition: blockchain.cpp:453
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)
Definition: blockchain.cpp:112
const RPCResult getblock_vin
Definition: blockchain.cpp:701
static RPCHelpMan syncwithvalidationinterfacequeue()
Definition: blockchain.cpp:433
static CBlockUndo GetUndoChecked(BlockManager &blockman, const CBlockIndex &blockindex)
Definition: blockchain.cpp:682
static std::vector< std::byte > GetRawBlockChecked(BlockManager &blockman, const CBlockIndex &blockindex)
Definition: blockchain.cpp:663
static RPCHelpMan getchaintips()
static RPCHelpMan loadtxoutset()
static RPCHelpMan gettxoutsetinfo()
Definition: blockchain.cpp:967
static RPCHelpMan getchainstates()
std::tuple< std::unique_ptr< CCoinsViewCursor >, CCoinsStats, const CBlockIndex * > PrepareUTXOSnapshot(Chainstate &chainstate, const std::function< void()> &interruption_point)
static std::atomic< int > g_scanfilter_progress_height
static RPCHelpMan getblockstats()
void CheckBlockDataAvailability(BlockManager &blockman, const CBlockIndex &blockindex, bool check_for_undo)
Definition: blockchain.cpp:631
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
static RPCHelpMan getdescriptoractivity()
double GetDifficulty(const CBlockIndex &blockindex)
Get the difficulty of the net wrt to the given block index.
Definition: blockchain.cpp:92
static const auto scan_objects_arg_desc
static RPCHelpMan scantxoutset()
CoinStatsHashType ParseHashType(const std::string &hash_type_input)
Definition: blockchain.cpp:924
static bool CheckBlockFilterMatches(BlockManager &blockman, const CBlockIndex &blockindex, const GCSFilter::ElementSet &needles)
void InvalidateBlock(ChainstateManager &chainman, const uint256 block_hash)
static std::atomic< int > g_scan_progress
RAII object to prevent concurrency issue when scanning the txout set.
static CBlock GetBlockChecked(BlockManager &blockman, const CBlockIndex &blockindex)
Definition: blockchain.cpp:646
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.
Definition: blockchain.cpp:840
UniValue blockToJSON(BlockManager &blockman, const CBlock &block, const CBlockIndex &tip, const CBlockIndex &blockindex, TxVerbosity verbosity, const uint256 pow_limit)
Block description to JSON.
Definition: blockchain.cpp:180
RPCHelpMan getdeploymentinfo()
static RPCHelpMan getblockfilter()
static RPCHelpMan getbestblockhash()
Definition: blockchain.cpp:242
RPCHelpMan getblockchaininfo()
void ReconsiderBlock(ChainstateManager &chainman, uint256 block_hash)
static RPCHelpMan getchaintxstats()
UniValue CreateUTXOSnapshot(node::NodeContext &node, Chainstate &chainstate, AutoFile &afile, const fs::path &path, const fs::path &tmppath)
Test-only helper to create UTXO snapshots given a chainstate and a file handle.
static RPCHelpMan waitforblock()
Definition: blockchain.cpp:309
std::tuple< std::unique_ptr< CCoinsViewCursor >, CCoinsStats, const CBlockIndex * > PrepareUTXOSnapshot(Chainstate &chainstate, const std::function< void()> &interruption_point={}) EXCLUSIVE_LOCKS_REQUIRED(UniValue WriteUTXOSnapshot(Chainstate &chainstate, CCoinsViewCursor *pcursor, CCoinsStats *maybe_stats, const CBlockIndex *tip, AutoFile &afile, const fs::path &path, const fs::path &temppath, const std::function< void()> &interruption_point={})
UniValue blockheaderToJSON(const CBlockIndex &tip, const CBlockIndex &blockindex, const uint256 pow_limit)
Block header to JSON.
Definition: blockchain.cpp:150
static RPCHelpMan getblockfrompeer()
Definition: blockchain.cpp:474
static const auto scan_result_status_some
static RPCHelpMan getblockhash()
Definition: blockchain.cpp:529
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.
Definition: blockchain.cpp:942
static RPCHelpMan gettxout()
static RPCHelpMan verifychain()
static std::atomic< bool > g_should_abort_scan
const std::vector< RPCResult > RPCHelpForChainstate
static const auto scan_action_arg_desc
static RPCHelpMan waitforblockheight()
Definition: blockchain.cpp:370
static const CBlockIndex * ParseHashOrHeight(const UniValue &param, ChainstateManager &chainman)
Definition: blockchain.cpp:122
static RPCHelpMan pruneblockchain()
Definition: blockchain.cpp:865
static RPCHelpMan getblockheader()
Definition: blockchain.cpp:559
static RPCHelpMan scanblocks()
static std::atomic< bool > g_scanfilter_in_progress
static RPCHelpMan dumptxoutset()
Serialize the UTXO set to a file for loading elsewhere.
static RPCHelpMan getblockcount()
Definition: blockchain.cpp:220
static RPCHelpMan waitfornewblock()
Definition: blockchain.cpp:263
static const auto scan_result_status_none
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.
Definition: chain.h:97
@ BLOCK_HAVE_UNDO
undo data available in rev*.dat
Definition: chain.h:122
@ 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
#define LIST_CHAIN_NAMES
List of possible chain / network names
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:102
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: args.h:234
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:393
bool IsNull() const
Return true if the wrapped FILE* is nullptr, false otherwise.
Definition: streams.h:429
int fclose()
Definition: streams.h:410
Complete block filter struct as defined in BIP 157.
Definition: blockfilter.h:115
const std::vector< unsigned char > & GetEncodedFilter() const LIFETIMEBOUND
Definition: blockfilter.h:138
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.
Definition: chainparams.h:101
const MessageStartChars & MessageStart() const
Definition: chainparams.h:82
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:81
uint64_t PruneAfterHeight() const
Definition: chainparams.h:93
ChainType GetChainType() const
Return the chain type.
Definition: chainparams.h:103
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:363
uint256 GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:173
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: coins.cpp:66
Cursor for iterating over CoinsView state.
Definition: coins.h:235
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:185
Abstract view on the open txout dataset.
Definition: coins.h:310
virtual uint256 GetBestBlock() const
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:17
CCoinsView that brings transactions from a mempool into view.
Definition: txmempool.h:925
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
GetCoin, returning whether it exists and is not spent.
Definition: txmempool.cpp:1027
Definition: net.h:1053
bool GetNetworkActive() const
Definition: net.h:1137
void SetNetworkActive(bool active)
Definition: net.cpp:3190
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
Txid hash
Definition: transaction.h:31
RPC command dispatcher.
Definition: server.h:127
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:415
An input of a transaction.
Definition: transaction.h:67
CTxMemPoolEntry stores data about the corresponding transaction, as well as data about all in-mempool...
Definition: mempool_entry.h:66
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
CTransactionRef get(const uint256 &hash) const
Definition: txmempool.cpp:884
std::vector< CTxMemPoolEntryRef > entryAll() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: txmempool.cpp:851
bool isSpent(const COutPoint &outpoint) const
Definition: txmempool.cpp:419
An output of a transaction.
Definition: transaction.h:150
CScript scriptPubKey
Definition: transaction.h:153
CAmount nValue
Definition: transaction.h:152
Undo information for a CTransaction.
Definition: undo.h:53
RAII wrapper for VerifyDB: Verify consistency of the block and coin databases.
Definition: validation.h:415
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:507
CChain m_chain
The current chain of blockheaders we consult and build on.
Definition: validation.h:587
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:613
void ForceFlushStateToDisk()
Unconditionally flush all changes to disk.
CCoinsViewDB & CoinsDB() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:621
ChainstateManager & m_chainman
The chainstate manager that owns this chainstate.
Definition: validation.h:547
node::BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all Chainstate instances.
Definition: validation.h:542
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:867
node::BlockMap & BlockIndex() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:1106
SnapshotCompletionResult MaybeCompleteSnapshotValidation() EXCLUSIVE_LOCKS_REQUIRED(const CBlockIndex *GetSnapshotBaseBlock() const EXCLUSIVE_LOCKS_REQUIRED(Chainstate ActiveChainstate)() const
Once the background validation chainstate has reached the height which is the base of the UTXO snapsh...
Definition: validation.h:1091
double GuessVerificationProgress(const CBlockIndex *pindex) const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Guess verification progress (as a fraction between 0.0=genesis and 1.0=current tip).
kernel::Notifications & GetNotifications() const
Definition: validation.h:980
bool IsInitialBlockDownload() const
Check whether we are doing an initial block download (synchronizing from disk or network)
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
Definition: validation.h:1000
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1094
VersionBitsCache m_versionbitscache
Track versionbit status.
Definition: validation.h:1115
const CChainParams & GetParams() const
Definition: validation.h:975
const Consensus::Params & GetConsensus() const
Definition: validation.h:976
util::Result< CBlockIndex * > ActivateSnapshot(AutoFile &coins_file, const node::SnapshotMetadata &metadata, bool in_memory)
Construct and activate a Chainstate on the basis of UTXO snapshot data.
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1092
Chainstate &InitializeChainstate(CTxMemPool *mempool) EXCLUSIVE_LOCKS_REQUIRED(std::vector< Chainstate * GetAll)()
Instantiate a new chainstate.
Definition: validation.h:1061
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
Definition: validation.h:1006
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
CoinsViewScanReserver()=default
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:148
std::unordered_set< Element, ByteVectorHash > ElementSet
Definition: blockfilter.h:32
RAII class that disables the network in its constructor and enables it in its destructor.
NetworkDisable(CConnman &connman)
CConnman & m_connman
virtual std::optional< std::string > FetchBlock(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:440
RAII class that temporarily rolls back the local chain in it's constructor and rolls it forward again...
TemporaryRollback(ChainstateManager &chainman, const CBlockIndex &index)
const CBlockIndex & m_invalidate_index
ChainstateManager & m_chainman
void push_back(UniValue val)
Definition: univalue.cpp:104
const std::string & get_str() const
@ VNULL
Definition: univalue.h:24
@ VOBJ
Definition: univalue.h:24
@ VARR
Definition: univalue.h:24
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:105
std::string ToString() const
Definition: validation.h:111
BIP9Info Info(const CBlockIndex &block_index, const Consensus::Params &params, Consensus::DeploymentPos id) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
std::string ToString() const
Definition: uint256.cpp:21
std::string GetHex() const
Definition: uint256.cpp:11
std::string GetHex() const
Hex encoding of the number (with the most significant digits first).
Interface giving clients (RPC, Stratum v2 Template Provider in the future) ability to create block te...
Definition: mining.h:80
virtual std::optional< BlockRef > waitTipChanged(uint256 current_tip, MillisecondsDouble timeout=MillisecondsDouble::max())=0
Waits for the connected tip to change.
virtual std::optional< BlockRef > getTip()=0
Returns the hash and height for the tip of this chain.
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
Definition: blockstorage.h:139
bool ReadBlock(CBlock &block, const FlatFilePos &pos, const std::optional< uint256 > &expected_hash={}) const
Functions for disk access for blocks.
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
bool ReadBlockUndo(CBlockUndo &blockundo, const CBlockIndex &index) const
uint64_t GetPruneTarget() const
Attempt to stay below this number of bytes of block files.
Definition: blockstorage.h:352
uint64_t CalculateCurrentUsage()
Calculate the amount of disk space the block & undo files currently use.
bool ReadRawBlock(std::vector< std::byte > &block, const FlatFilePos &pos) const
bool IsPruneMode() const
Whether running in -prune mode.
Definition: blockstorage.h:349
Metadata describing a serialized version of a UTXO set from which an assumeutxo Chainstate can be con...
Definition: utxo_snapshot.h:34
constexpr const std::byte * begin() const
std::string GetHex() const
static transaction_identifier FromUint256(const uint256 &id)
256-bit opaque blob.
Definition: uint256.h:196
std::unique_ptr< CoinStatsIndex > g_coin_stats_index
The global UTXO set hash object.
static int64_t GetBlockWeight(const CBlock &block)
Definition: validation.h:136
static int32_t GetTransactionWeight(const CTransaction &tx)
Definition: validation.h:132
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)
Definition: core_write.cpp:171
TxVerbosity
Verbose level for block's transaction.
Definition: core_io.h:28
@ 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)
Definition: core_write.cpp:150
UniValue ValueFromAmount(const CAmount amount)
Definition: core_write.cpp:26
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
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
#define T(expected, seed, data)
std::string HexStr(const std::span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
Definition: hex_base.cpp:29
#define LogWarning(...)
Definition: logging.h:262
#define LogDebug(category,...)
Definition: logging.h:280
unsigned int nHeight
static void pool cs
@ RPC
Definition: logging.h:50
@ NONE
Definition: logging.h:42
DeploymentPos
Definition: params.h:33
@ DEPLOYMENT_TAPROOT
Definition: params.h:35
@ DEPLOYMENT_TESTDUMMY
Definition: params.h:34
BuriedDeployment
A buried deployment is one where the height of the activation has been hardcoded into the client impl...
Definition: params.h:23
@ DEPLOYMENT_DERSIG
Definition: params.h:27
@ DEPLOYMENT_CSV
Definition: params.h:28
@ DEPLOYMENT_SEGWIT
Definition: params.h:29
@ DEPLOYMENT_HEIGHTINCB
Definition: params.h:25
@ DEPLOYMENT_CLTV
Definition: params.h:26
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.
Definition: coinstats.cpp:116
CoinStatsHashType
Definition: coinstats.h:26
Definition: messages.h:20
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:213
int64_t NodeId
Definition: net.h:98
static constexpr TransactionSerParams TX_NO_WITNESS
Definition: transaction.h:196
static constexpr TransactionSerParams TX_WITH_WITNESS
Definition: transaction.h:195
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:423
@ 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:1327
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:186
uint256 GetTarget(const CBlockIndex &blockindex, const uint256 pow_limit)
Definition: util.cpp:1404
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:204
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:46
std::string GetAllOutputTypes()
Gets all existing output types formatted for RPC help sections.
Definition: util.cpp:49
int ParseVerbosity(const UniValue &arg, int default_verbosity, bool allow_bool)
Parses verbosity from provided UniValue.
Definition: util.cpp:86
uint256 ParseHashV(const UniValue &v, std::string_view name)
Utilities: convert hex-encoded Values (throws error if not hex).
Definition: util.cpp:120
std::vector< RPCResult > ScriptPubKeyDoc()
Definition: util.cpp:1393
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:1105
void WriteCompactSize(SizeComputer &os, uint64_t nSize)
Definition: serialize.h:1099
bool IsDeprecatedRPCEnabled(const std::string &method)
Definition: server.cpp:345
ChainstateManager & EnsureAnyChainman(const std::any &context)
Definition: server_util.cpp:82
NodeContext & EnsureAnyNodeContext(const std::any &context)
Definition: server_util.cpp:25
CTxMemPool & EnsureMemPool(const NodeContext &node)
Definition: server_util.cpp:34
PeerManager & EnsurePeerman(const NodeContext &node)
ChainstateManager & EnsureChainman(const NodeContext &node)
Definition: server_util.cpp:74
ArgsManager & EnsureArgsman(const NodeContext &node)
Definition: server_util.cpp:61
interfaces::Mining & EnsureMining(const NodeContext &node)
CConnman & EnsureConnman(const NodeContext &node)
ArgsManager & EnsureAnyArgsman(const std::any &context)
Definition: server_util.cpp:69
unsigned char * UCharCast(char *c)
Definition: span.h:95
Detailed status of an enabled BIP9 deployment.
Definition: versionbits.h:50
Comparison function for sorting the getchaintips heads.
bool operator()(const CBlockIndex *a, const CBlockIndex *b) const
std::vector< uint8_t > signet_challenge
Definition: params.h:136
uint256 powLimit
Proof of work parameters.
Definition: params.h:111
int DeploymentHeight(BuriedDeployment dep) const
Definition: params.h:138
std::array< BIP9Deployment, MAX_VERSION_BITS_DEPLOYMENTS > vDeployments
Definition: params.h:109
int64_t nPowTargetSpacing
Definition: params.h:119
Definition: util.h:182
@ 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:216
@ OMITTED
Optional argument for which the default value is omitted from help text for one of two reasons:
@ NO
Required arg.
UniValue Default
Default constant value.
Definition: util.h:218
std::string oneline_description
Should be empty unless it is supposed to override the auto-generated summary line.
Definition: util.h:167
bool skip_type_check
Definition: util.h:166
@ 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.
Hash/height pair to help track and identify blocks.
Definition: types.h:13
std::optional< CAmount > total_amount
The total amount, or nullopt if an overflow occurred calculating it.
Definition: coinstats.h:41
uint64_t nDiskSize
Definition: coinstats.h:39
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
uint64_t coins_count
The number of coins contained.
Definition: coinstats.h:44
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
uint64_t nBogoSize
Definition: coinstats.h:37
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:56
#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:302
static int count
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:49
#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...
Definition: tinyformat.h:1172
consteval auto _(util::TranslatedLiteral str)
Definition: translation.h:79
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
std::chrono::duration< double, std::chrono::milliseconds::period > MillisecondsDouble
Definition: time.h:88
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams)
const std::vector< std::string > CHECKLEVEL_DOC
Documentation for argument 'checklevel'.
Definition: validation.cpp:101
void PruneBlockFilesManual(Chainstate &active_chainstate, int nManualPruneHeight)
Prune block files up to a given height.
AssertLockHeld(pool.cs)
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:71
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:69
static const signed int DEFAULT_CHECKBLOCKS
Definition: validation.h:70