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