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