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