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