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