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