Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1751}1753void InvalidateBlock(ChainstateManager& chainman, const uint256 block_hash) {1754BlockValidationState state;1755CBlockIndex* pblockindex;1756{1757LOCK(chainman.GetMutex());1758pblockindex = chainman.m_blockman.LookupBlockIndex(block_hash);1759if (!pblockindex) {1760throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");1761}1762}1763chainman.ActiveChainstate().InvalidateBlock(state, pblockindex);1765if (state.IsValid()) {1766chainman.ActiveChainstate().ActivateBestChain(state);1767}1769if (!state.IsValid()) {1770throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());1771}1772}1774static RPCMethod invalidateblock()1775{1776return RPCMethod{1777"invalidateblock",1778"Permanently marks a block as invalid, as if it violated a consensus rule.\n",1779{1780{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as invalid"},1781},1782RPCResult{RPCResult::Type::NONE, "", ""},1783RPCExamples{1784HelpExampleCli("invalidateblock", "\"blockhash\"")1785+ HelpExampleRpc("invalidateblock", "\"blockhash\"")1786},1787[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue1788{1789ChainstateManager& chainman = EnsureAnyChainman(request.context);1790uint256 hash(ParseHashV(request.params[0], "blockhash"));1792InvalidateBlock(chainman, hash);1794return UniValue::VNULL;1795},1796};1797}1799void ReconsiderBlock(ChainstateManager& chainman, uint256 block_hash) {1800{1801LOCK(chainman.GetMutex());1802CBlockIndex* pblockindex = chainman.m_blockman.LookupBlockIndex(block_hash);1803if (!pblockindex) {1804throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");1805}1807chainman.ActiveChainstate().ResetBlockFailureFlags(pblockindex);1808chainman.RecalculateBestHeader();1809}1811BlockValidationState state;1812chainman.ActiveChainstate().ActivateBestChain(state);1814if (!state.IsValid()) {1815throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());1816}1817}1819static RPCMethod reconsiderblock()1820{1821return RPCMethod{1822"reconsiderblock",1823"Removes invalidity status of a block, its ancestors and its descendants, reconsider them for activation.\n"1824"This can be used to undo the effects of invalidateblock.\n",1825{1826{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to reconsider"},1827},1828RPCResult{RPCResult::Type::NONE, "", ""},1829RPCExamples{1830HelpExampleCli("reconsiderblock", "\"blockhash\"")1831+ HelpExampleRpc("reconsiderblock", "\"blockhash\"")1832},1833[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue1834{1835ChainstateManager& chainman = EnsureAnyChainman(request.context);1836uint256 hash(ParseHashV(request.params[0], "blockhash"));1838ReconsiderBlock(chainman, hash);1840return UniValue::VNULL;1841},1842};1843}1845static RPCMethod getchaintxstats()1846{1847return RPCMethod{1848"getchaintxstats",1849"Compute statistics about the total number and rate of transactions in the chain.\n",1850{1851{"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{"one month"}, "Size of the window in number of blocks"},1852{"blockhash", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"chain tip"}, "The hash of the block that ends the window."},1853},1854RPCResult{1855RPCResult::Type::OBJ, "", "",1856{1857{RPCResult::Type::NUM_TIME, "time", "The timestamp for the final block in the window, expressed in " + UNIX_EPOCH_TIME},1858{RPCResult::Type::NUM, "txcount", /*optional=*/true,1859"The total number of transactions in the chain up to that point, if known. "1860"It may be unknown when using assumeutxo."},1861{RPCResult::Type::STR_HEX, "window_final_block_hash", "The hash of the final block in the window"},1862{RPCResult::Type::NUM, "window_final_block_height", "The height of the final block in the window."},1863{RPCResult::Type::NUM, "window_block_count", "Size of the window in number of blocks"},1864{RPCResult::Type::NUM, "window_interval", /*optional=*/true, "The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0"},1865{RPCResult::Type::NUM, "window_tx_count", /*optional=*/true,1866"The number of transactions in the window. "1867"Only returned if \"window_block_count\" is > 0 and if txcount exists for the start and end of the window."},1868{RPCResult::Type::NUM, "txrate", /*optional=*/true,1869"The average rate of transactions per second in the window. "1870"Only returned if \"window_interval\" is > 0 and if window_tx_count exists."},1871}},1872RPCExamples{1873HelpExampleCli("getchaintxstats", "")1874+ HelpExampleRpc("getchaintxstats", "2016")1875},1876[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue1877{1878ChainstateManager& chainman = EnsureAnyChainman(request.context);1879const CBlockIndex* pindex;1880int blockcount = 30 * 24 * 60 * 60 / chainman.GetParams().GetConsensus().nPowTargetSpacing; // By default: 1 month1882if (request.params[1].isNull()) {1883LOCK(cs_main);1884pindex = chainman.ActiveChain().Tip();1885} else {1886uint256 hash(ParseHashV(request.params[1], "blockhash"));1887LOCK(cs_main);1888pindex = chainman.m_blockman.LookupBlockIndex(hash);1889if (!pindex) {1890throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");1891}1892if (!chainman.ActiveChain().Contains(*pindex)) {1893throw JSONRPCError(RPC_INVALID_PARAMETER, "Block is not in main chain");1894}1895}1897CHECK_NONFATAL(pindex != nullptr);1899if (request.params[0].isNull()) {1900blockcount = std::max(0, std::min(blockcount, pindex->nHeight - 1));1901} else {1902blockcount = request.params[0].getInt<int>();1904if (blockcount < 0 || (blockcount > 0 && blockcount >= pindex->nHeight)) {1905throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block count: should be between 0 and the block's height - 1");1906}1907}1909const CBlockIndex& past_block{*CHECK_NONFATAL(pindex->GetAncestor(pindex->nHeight - blockcount))};1910const int64_t nTimeDiff{pindex->GetMedianTimePast() - past_block.GetMedianTimePast()};1912UniValue ret(UniValue::VOBJ);1913ret.pushKV("time", pindex->nTime);1914if (pindex->m_chain_tx_count) {1915ret.pushKV("txcount", pindex->m_chain_tx_count);1916}1917ret.pushKV("window_final_block_hash", pindex->GetBlockHash().GetHex());1918ret.pushKV("window_final_block_height", pindex->nHeight);1919ret.pushKV("window_block_count", blockcount);1920if (blockcount > 0) {1921ret.pushKV("window_interval", nTimeDiff);1922if (pindex->m_chain_tx_count != 0 && past_block.m_chain_tx_count != 0) {1923const auto window_tx_count = pindex->m_chain_tx_count - past_block.m_chain_tx_count;1924ret.pushKV("window_tx_count", window_tx_count);1925if (nTimeDiff > 0) {1926ret.pushKV("txrate", double(window_tx_count) / nTimeDiff);1927}1928}1929}1931return ret;1932},1933};1934}1936template<typename T>1937static T CalculateTruncatedMedian(std::vector<T>& scores)1938{1939size_t size = scores.size();1940if (size == 0) {1941return 0;1942}1944std::sort(scores.begin(), scores.end());1945if (size % 2 == 0) {1946return (scores[size / 2 - 1] + scores[size / 2]) / 2;1947} else {1948return scores[size / 2];1949}1950}1952void CalculatePercentilesByWeight(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_weight)1953{1954if (scores.empty()) {1955return;1956}1958std::sort(scores.begin(), scores.end());1960// 10th, 25th, 50th, 75th, and 90th percentile weight units.1961const double weights[NUM_GETBLOCKSTATS_PERCENTILES] = {1962total_weight / 10.0, total_weight / 4.0, total_weight / 2.0, (total_weight * 3.0) / 4.0, (total_weight * 9.0) / 10.01963};1965int64_t next_percentile_index = 0;1966int64_t cumulative_weight = 0;1967for (const auto& element : scores) {1968cumulative_weight += element.second;1969while (next_percentile_index < NUM_GETBLOCKSTATS_PERCENTILES && cumulative_weight >= weights[next_percentile_index]) {1970result[next_percentile_index] = element.first;1971++next_percentile_index;1972}1973}1975// Fill any remaining percentiles with the last value.1976for (int64_t i = next_percentile_index; i < NUM_GETBLOCKSTATS_PERCENTILES; i++) {1977result[i] = scores.back().first;1978}1979}1981template<typename T>1982static inline bool SetHasKeys(const std::set<T>& set) {return false;}1983template<typename T, typename Tk, typename... Args>1984static inline bool SetHasKeys(const std::set<T>& set, const Tk& key, const Args&... args)1985{1986return (set.contains(key)) || SetHasKeys(set, args...);1987}1989// outpoint (needed for the utxo index) + nHeight|fCoinBase1990static constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t);1992static RPCMethod getblockstats()1993{1994return RPCMethod{1995"getblockstats",1996"Compute per block statistics for a given window. All amounts are in satoshis.\n"1997"It won't work for some heights with pruning.\n",1998{1999{"hash_or_height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block hash or height of the target block",2000RPCArgOptions{