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