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