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.
1501return obj;1502},1503};1504}1506namespace {1507const std::vector<RPCResult> RPCHelpForDeployment{1508{RPCResult::Type::STR, "type", "one of \"buried\", \"bip9\""},1509{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)"},1510{RPCResult::Type::BOOL, "active", "true if the rules are enforced for the mempool and the next block"},1511{RPCResult::Type::OBJ, "bip9", /*optional=*/true, "status of bip9 softforks (only for \"bip9\" type)",1512{1513{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)"},1514{RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"},1515{RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"},1516{RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"},1517{RPCResult::Type::STR, "status", "status of deployment at specified block (one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\")"},1518{RPCResult::Type::NUM, "since", "height of the first block to which the status applies"},1519{RPCResult::Type::STR, "status_next", "status of deployment at the next block"},1520{RPCResult::Type::OBJ, "statistics", /*optional=*/true, "numeric statistics about signalling for a softfork (only for \"started\" and \"locked_in\" status)",1521{1522{RPCResult::Type::NUM, "period", "the length in blocks of the signalling period"},1523{RPCResult::Type::NUM, "threshold", /*optional=*/true, "the number of blocks with the version bit set required to activate the feature (only for \"started\" status)"},1524{RPCResult::Type::NUM, "elapsed", "the number of blocks elapsed since the beginning of the current period"},1525{RPCResult::Type::NUM, "count", "the number of blocks with the version bit set in the current period"},1526{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)"},1527}},1528{RPCResult::Type::STR, "signalling", /*optional=*/true, "indicates blocks that signalled with a # and blocks that did not with a -"},1529}},1530};1532UniValue DeploymentInfo(const CBlockIndex* blockindex, const ChainstateManager& chainman)1533{1534UniValue softforks(UniValue::VOBJ);1535SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_HEIGHTINCB);1536SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_DERSIG);1537SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_CLTV);1538SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_CSV);1539SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_SEGWIT);1540SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TESTDUMMY);1541return softforks;1542}1543} // anon namespace1545RPCMethod getdeploymentinfo()1546{1547return RPCMethod{"getdeploymentinfo",1548"Returns an object containing various state info regarding deployments of consensus changes.\n"1549"Consensus changes for which the new rules are enforced from genesis are not listed in \"deployments\".",1550{1551{"blockhash", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"hash of current chain tip"}, "The block hash at which to query deployment state"},1552},1553RPCResult{1554RPCResult::Type::OBJ, "", "", {1555{RPCResult::Type::STR, "hash", "requested block hash (or tip)"},1556{RPCResult::Type::NUM, "height", "requested block height (or tip)"},1557{RPCResult::Type::ARR, "script_flags", "script verify flags for the block", {1558{RPCResult::Type::STR, "flag", "a script verify flag"},1559}},1560{RPCResult::Type::OBJ_DYN, "deployments", "", {1561{RPCResult::Type::OBJ, "xxxx", "name of the deployment", RPCHelpForDeployment}1562}},1563}1564},1565RPCExamples{ HelpExampleCli("getdeploymentinfo", "") + HelpExampleRpc("getdeploymentinfo", "") },1566[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue1567{1568const ChainstateManager& chainman = EnsureAnyChainman(request.context);1569LOCK(cs_main);1570const Chainstate& active_chainstate = chainman.ActiveChainstate();1572const CBlockIndex* blockindex;1573if (request.params[0].isNull()) {1574blockindex = CHECK_NONFATAL(active_chainstate.m_chain.Tip());1575} else {1576const uint256 hash(ParseHashV(request.params[0], "blockhash"));1577blockindex = chainman.m_blockman.LookupBlockIndex(hash);1578if (!blockindex) {1579throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");1580}1581}1583UniValue deploymentinfo(UniValue::VOBJ);1584deploymentinfo.pushKV("hash", blockindex->GetBlockHash().ToString());1585deploymentinfo.pushKV("height", blockindex->nHeight);1586{1587const auto flagnames = GetScriptFlagNames(GetBlockScriptFlags(*blockindex, chainman));1588UniValue uv_flagnames(UniValue::VARR);1589uv_flagnames.push_backV(flagnames.begin(), flagnames.end());1590deploymentinfo.pushKV("script_flags", uv_flagnames);1591}1592deploymentinfo.pushKV("deployments", DeploymentInfo(blockindex, chainman));1593return deploymentinfo;1594},1595};1596}1598/** Comparison function for sorting the getchaintips heads. */1599struct CompareBlocksByHeight1600{1601bool operator()(const CBlockIndex* a, const CBlockIndex* b) const1602{1603/* Make sure that unequal blocks with the same height do not compare1604equal. Use the pointers themselves to make a distinction. */1606if (a->nHeight != b->nHeight)1607return (a->nHeight > b->nHeight);1609return a < b;1610}1611};1613static RPCMethod getchaintips()1614{1615return RPCMethod{"getchaintips",1616"Return information about all known tips in the block tree,"1617" including the main chain as well as orphaned branches.\n",1618{},1619RPCResult{1620RPCResult::Type::ARR, "", "",1621{{RPCResult::Type::OBJ, "", "",1622{1623{RPCResult::Type::NUM, "height", "height of the chain tip"},1624{RPCResult::Type::STR_HEX, "hash", "block hash of the tip"},1625{RPCResult::Type::NUM, "branchlen", "zero for main chain, otherwise length of branch connecting the tip to the main chain"},1626{RPCResult::Type::STR, "status", "status of the chain, \"active\" for the main chain\n"1627"Possible values for status:\n"1628"1. \"invalid\" This branch contains at least one invalid block\n"1629"2. \"headers-only\" Not all blocks for this branch are available, but the headers are valid\n"1630"3. \"valid-headers\" All blocks are available for this branch, but they were never fully validated\n"1631"4. \"valid-fork\" This branch is not part of the active chain, but is fully validated\n"1632"5. \"active\" This is the tip of the active main chain, which is certainly valid"},1633}}}},1634RPCExamples{1635HelpExampleCli("getchaintips", "")1636+ HelpExampleRpc("getchaintips", "")1637},1638[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue1639{1640ChainstateManager& chainman = EnsureAnyChainman(request.context);1641LOCK(cs_main);1642CChain& active_chain = chainman.ActiveChain();1644/*1645* Idea: The set of chain tips is the active chain tip, plus orphan blocks which do not have another orphan building off of them.1646* Algorithm:1647* - Make one pass through BlockIndex(), picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers.1648* - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip.1649* - Add the active chain tip1650*/1651std::set<const CBlockIndex*, CompareBlocksByHeight> setTips;1652std::set<const CBlockIndex*> setOrphans;1653std::set<const CBlockIndex*> setPrevs;1655for (const auto& [_, block_index] : chainman.BlockIndex()) {1656if (!active_chain.Contains(block_index)) {1657setOrphans.insert(&block_index);1658setPrevs.insert(block_index.pprev);1659}1660}1662for (std::set<const CBlockIndex*>::iterator it = setOrphans.begin(); it != setOrphans.end(); ++it) {1663if (setPrevs.erase(*it) == 0) {1664setTips.insert(*it);1665}1666}1668// Always report the currently active tip.1669setTips.insert(active_chain.Tip());1671/* Construct the output array. */1672UniValue res(UniValue::VARR);1673for (const CBlockIndex* block : setTips) {1674CHECK_NONFATAL(block);1675UniValue obj(UniValue::VOBJ);1676obj.pushKV("height", block->nHeight);1677obj.pushKV("hash", block->phashBlock->GetHex());1679const int branchLen = block->nHeight - active_chain.FindFork(*block)->nHeight;1680obj.pushKV("branchlen", branchLen);1682std::string status;1683if (active_chain.Contains(*block)) {1684// This block is part of the currently active chain.1685status = "active";1686} else if (block->nStatus & BLOCK_FAILED_VALID) {1687// This block or one of its ancestors is invalid.1688status = "invalid";1689} else if (!block->HaveNumChainTxs()) {1690// This block cannot be connected because full block data for it or one of its parents is missing.1691status = "headers-only";1692} else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {1693// This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.1694status = "valid-fork";1695} else if (block->IsValid(BLOCK_VALID_TREE)) {1696// The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.1697status = "valid-headers";1698} else {1699// No clue.1700status = "unknown";1701}1702obj.pushKV("status", status);1704res.push_back(std::move(obj));1705}1707return res;1708},1709};1710}1712static RPCMethod preciousblock()1713{1714return RPCMethod{1715"preciousblock",1716"Treats a block as if it were received before others with the same work.\n"1717"\nA later preciousblock call can override the effect of an earlier one.\n"1718"\nThe effects of preciousblock are not retained across restarts.\n",1719{1720{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as precious"},1721},1722RPCResult{RPCResult::Type::NONE, "", ""},1723RPCExamples{1724HelpExampleCli("preciousblock", "\"blockhash\"")1725+ HelpExampleRpc("preciousblock", "\"blockhash\"")1726},1727[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue1728{1729uint256 hash(ParseHashV(request.params[0], "blockhash"));1730CBlockIndex* pblockindex;1732ChainstateManager& chainman = EnsureAnyChainman(request.context);1733{1734LOCK(cs_main);1735pblockindex = chainman.m_blockman.LookupBlockIndex(hash);1736if (!pblockindex) {1737throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");1738}1739}1741BlockValidationState state;1742chainman.ActiveChainstate().PreciousBlock(state, pblockindex);1744if (!state.IsValid()) {1745throw JSONRPCError(RPC_DATABASE_ERROR, state.ToString());1746}1748return UniValue::VNULL;1749},1750};