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