| 1904 | }; |
| 1905 | |
| 1906 | static RPCHelpMan getchaintips() |
| 1907 | { |
| 1908 | return RPCHelpMan{"getchaintips", |
| 1909 | "Return information about all known tips in the block tree," |
| 1910 | " including the main chain as well as orphaned branches.\n", |
| 1911 | {}, |
| 1912 | RPCResult{ |
| 1913 | RPCResult::Type::ARR, "", "", |
| 1914 | {{RPCResult::Type::OBJ, "", "", |
| 1915 | { |
| 1916 | {RPCResult::Type::NUM, "height", "height of the chain tip"}, |
| 1917 | {RPCResult::Type::STR_HEX, "hash", "block hash of the tip"}, |
| 1918 | {RPCResult::Type::NUM, "branchlen", "zero for main chain, otherwise length of branch connecting the tip to the main chain"}, |
| 1919 | {RPCResult::Type::STR, "status", "status of the chain, \"active\" for the main chain\n" |
| 1920 | "Possible values for status:\n" |
| 1921 | "1. \"invalid\" This branch contains at least one invalid block\n" |
| 1922 | "2. \"headers-only\" Not all blocks for this branch are available, but the headers are valid\n" |
| 1923 | "3. \"valid-headers\" All blocks are available for this branch, but they were never fully validated\n" |
| 1924 | "4. \"valid-fork\" This branch is not part of the active chain, but is fully validated\n" |
| 1925 | "5. \"active\" This is the tip of the active main chain, which is certainly valid"}, |
| 1926 | }}}}, |
| 1927 | RPCExamples{ |
| 1928 | HelpExampleCli("getchaintips", "") |
| 1929 | + HelpExampleRpc("getchaintips", "") |
| 1930 | }, |
| 1931 | [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue |
| 1932 | { |
| 1933 | ChainstateManager& chainman = EnsureAnyChainman(request.context); |
| 1934 | LOCK(cs_main); |
| 1935 | CChain& active_chain = chainman.ActiveChain(); |
| 1936 | |
| 1937 | /* |
| 1938 | * Idea: The set of chain tips is the active chain tip, plus orphan blocks which do not have another orphan building off of them. |
| 1939 | * Algorithm: |
| 1940 | * - Make one pass through BlockIndex(), picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers. |
| 1941 | * - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip. |
| 1942 | * - Add the active chain tip |
| 1943 | */ |
| 1944 | std::set<const CBlockIndex*, CompareBlocksByHeight> setTips; |
| 1945 | std::set<const CBlockIndex*> setOrphans; |
| 1946 | std::set<const CBlockIndex*> setPrevs; |
| 1947 | |
| 1948 | for (const std::pair<const uint256, CBlockIndex*>& item : chainman.BlockIndex()) { |
| 1949 | if (!active_chain.Contains(item.second)) { |
| 1950 | setOrphans.insert(item.second); |
| 1951 | setPrevs.insert(item.second->pprev); |
| 1952 | } |
| 1953 | } |
| 1954 | |
| 1955 | for (std::set<const CBlockIndex*>::iterator it = setOrphans.begin(); it != setOrphans.end(); ++it) { |
| 1956 | if (setPrevs.erase(*it) == 0) { |
| 1957 | setTips.insert(*it); |
| 1958 | } |
| 1959 | } |
| 1960 | |
| 1961 | // Always report the currently active tip. |
| 1962 | setTips.insert(active_chain.Tip()); |
| 1963 |
nothing calls this directly
no test coverage detected