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