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.
1751if (par_idx == par2_idx && chl_idx == chl2_idx) continue;1752if (expected_top[par2_idx] || expected_top[chl2_idx]) {1753expected_top.Set(par2_idx);1754expected_top.Set(chl2_idx);1755++active_dep_count;1756}1757}1758if (old == expected_top) {1759assert(expected_top.Count() == active_dep_count + 1);1760break;1761}1762}1763assert(!expected_top[chl_idx]);1764auto& dep_top_info = m_set_info[m_tx_data[par_idx].dep_top_idx[chl_idx]];1765assert(dep_top_info.transactions == expected_top);1766// Verify the top set's feerate.1767assert(dep_top_info.feerate == m_depgraph.FeeRate(dep_top_info.transactions));1768}1770//1771// Verify m_suboptimal_chunks.1772//1773SetType suboptimal_idxs;1774for (size_t i = 0; i < m_suboptimal_chunks.size(); ++i) {1775auto chunk_idx = m_suboptimal_chunks[i];1776assert(!suboptimal_idxs[chunk_idx]);1777suboptimal_idxs.Set(chunk_idx);1778}1779assert(m_suboptimal_idxs == suboptimal_idxs);1781//1782// Verify m_nonminimal_chunks.1783//1784SetType nonminimal_idxs;1785for (size_t i = 0; i < m_nonminimal_chunks.size(); ++i) {1786auto [chunk_idx, pivot, flags] = m_nonminimal_chunks[i];1787assert(m_tx_data[pivot].chunk_idx == chunk_idx);1788assert(!nonminimal_idxs[chunk_idx]);1789nonminimal_idxs.Set(chunk_idx);1790}1791assert(nonminimal_idxs.IsSubsetOf(m_chunk_idxs));1792}1793};1795/** Find or improve a linearization for a cluster.1796*1797* @param[in] depgraph Dependency graph of the cluster to be linearized.1798* @param[in] max_cost Upper bound on the amount of work that will be done.1799* @param[in] rng_seed A random number seed to control search order. This prevents peers1800* from predicting exactly which clusters would be hard for us to1801* linearize.1802* @param[in] fallback_order A comparator to order transactions, used to sort equal-feerate1803* chunks and transactions. See SpanningForestState::GetLinearization1804* for details.1805* @param[in] old_linearization An existing linearization for the cluster, or empty.1806* @param[in] is_topological (Only relevant if old_linearization is not empty) Whether1807* old_linearization is topologically valid.1808* @return A tuple of:1809* - The resulting linearization. It is guaranteed to be at least as1810* good (in the feerate diagram sense) as old_linearization.1811* - A boolean indicating whether the result is guaranteed to be1812* optimal with minimal chunks.1813* - How many optimization steps were actually performed.1814*/1815template<typename SetType>1816std::tuple<std::vector<DepGraphIndex>, bool, uint64_t> Linearize(1817const DepGraph<SetType>& depgraph,1818uint64_t max_cost,1819uint64_t rng_seed,1820const StrongComparator<DepGraphIndex> auto& fallback_order,1821std::span<const DepGraphIndex> old_linearization = {},1822bool is_topological = true) noexcept1823{1824/** Initialize a spanning forest data structure for this cluster. */1825SpanningForestState forest(depgraph, rng_seed);1826if (!old_linearization.empty()) {1827forest.LoadLinearization(old_linearization);1828if (!is_topological) forest.MakeTopological();1829} else {1830forest.MakeTopological();1831}1832// Make improvement steps to it until we hit the max_iterations limit, or an optimal result1833// is found.1834if (forest.GetCost() < max_cost) {1835forest.StartOptimizing();1836do {1837if (!forest.OptimizeStep()) break;1838} while (forest.GetCost() < max_cost);1839}1840// Make chunk minimization steps until we hit the max_iterations limit, or all chunks are1841// minimal.1842bool optimal = false;1843if (forest.GetCost() < max_cost) {1844forest.StartMinimizing();1845do {1846if (!forest.MinimizeStep()) {1847optimal = true;1848break;1849}1850} while (forest.GetCost() < max_cost);1851}1852return {forest.GetLinearization(fallback_order), optimal, forest.GetCost()};1853}1855/** Improve a given linearization.1856*1857* @param[in] depgraph Dependency graph of the cluster being linearized.1858* @param[in,out] linearization On input, an existing linearization for depgraph. On output, a1859* potentially better linearization for the same graph.1860*1861* Postlinearization guarantees:1862* - The resulting chunks are connected.1863* - If the input has a tree shape (either all transactions have at most one child, or all1864* transactions have at most one parent), the result is optimal.1865* - Given a linearization L1 and a leaf transaction T in it. Let L2 be L1 with T moved to the end,1866* optionally with its fee increased. Let L3 be the postlinearization of L2. L3 will be at least1867* as good as L1. This means that replacing transactions with same-size higher-fee transactions1868* will not worsen linearizations through a "drop conflicts, append new transactions,1869* postlinearize" process.1870*/1871template<typename SetType>1872void PostLinearize(const DepGraph<SetType>& depgraph, std::span<DepGraphIndex> linearization)1873{1874// This algorithm performs a number of passes (currently 2); the even ones operate from back to1875// front, the odd ones from front to back. Each results in an equal-or-better linearization1876// than the one started from.1877// - One pass in either direction guarantees that the resulting chunks are connected.1878// - Each direction corresponds to one shape of tree being linearized optimally (forward passes1879// guarantee this for graphs where each transaction has at most one child; backward passes1880// guarantee this for graphs where each transaction has at most one parent).1881// - Starting with a backward pass guarantees the moved-tree property.1882//1883// During an odd (forward) pass, the high-level operation is:1884// - Start with an empty list of groups L=[].1885// - For every transaction i in the old linearization, from front to back:1886// - Append a new group C=[i], containing just i, to the back of L.1887// - While L has at least one group before C, and the group immediately before C has feerate1888// lower than C:1889// - If C depends on P:1890// - Merge P into C, making C the concatenation of P+C, continuing with the combined C.1891// - Otherwise:1892// - Swap P with C, continuing with the now-moved C.1893// - The output linearization is the concatenation of the groups in L.1894//1895// During even (backward) passes, i iterates from the back to the front of the existing1896// linearization, and new groups are prepended instead of appended to the list L. To enable1897// more code reuse, both passes append groups, but during even passes the meanings of1898// parent/child, and of high/low feerate are reversed, and the final concatenation is reversed1899// on output.1900//1901// In the implementation below, the groups are represented by singly-linked lists (pointing1902// from the back to the front), which are themselves organized in a singly-linked circular1903// list (each group pointing to its predecessor, with a special sentinel group at the front1904// that points back to the last group).1905//1906// Information about transaction t is stored in entries[t + 1], while the sentinel is in1907// entries[0].1909/** Index of the sentinel in the entries array below. */1910static constexpr DepGraphIndex SENTINEL{0};1911/** Indicator that a group has no previous transaction. */1912static constexpr DepGraphIndex NO_PREV_TX{0};1915/** Data structure per transaction entry. */1916struct TxEntry1917{1918/** The index of the previous transaction in this group; NO_PREV_TX if this is the first1919* entry of a group. */1920DepGraphIndex prev_tx;1922// The fields below are only used for transactions that are the last one in a group1923// (referred to as tail transactions below).1925/** Index of the first transaction in this group, possibly itself. */1926DepGraphIndex first_tx;1927/** Index of the last transaction in the previous group. The first group (the sentinel)1928* points back to the last group here, making it a singly-linked circular list. */1929DepGraphIndex prev_group;1930/** All transactions in the group. Empty for the sentinel. */1931SetType group;1932/** All dependencies of the group (descendants in even passes; ancestors in odd ones). */1933SetType deps;1934/** The combined fee/size of transactions in the group. Fee is negated in even passes. */1935FeeFrac feerate;1936};1938// As an example, consider the state corresponding to the linearization [1,0,3,2], with1939// groups [1,0,3] and [2], in an odd pass. The linked lists would be:1940//1941// +-----+1942// 0<-P-- | 0 S | ---\ Legend:1943// +-----+ |1944// ^ | - digit in box: entries index1945// /--------------F---------+ G | (note: one more than tx value)1946// v \ | | - S: sentinel group1947// +-----+ +-----+ +-----+ | (empty feerate)1948// 0<-P-- | 2 | <--P-- | 1 | <--P-- | 4 T | | - T: tail transaction, contains1949// +-----+ +-----+ +-----+ | fields beyond prev_tv.1950// ^ | - P: prev_tx reference1951// G G - F: first_tx reference1952// | | - G: prev_group reference1953// +-----+ |1954// 0<-P-- | 3 T | <--/1955// +-----+1956// ^ |1957// \-F-/1958//1959// During an even pass, the diagram above would correspond to linearization [2,3,0,1], with1960// groups [2] and [3,0,1].1962std::vector<TxEntry> entries(depgraph.PositionRange() + 1);1964// Perform two passes over the linearization.1965for (int pass = 0; pass < 2; ++pass) {1966int rev = !(pass & 1);1967// Construct a sentinel group, identifying the start of the list.1968entries[SENTINEL].prev_group = SENTINEL;1969Assume(entries[SENTINEL].feerate.IsEmpty());1971// Iterate over all elements in the existing linearization.1972for (DepGraphIndex i = 0; i < linearization.size(); ++i) {1973// Even passes are from back to front; odd passes from front to back.1974DepGraphIndex idx = linearization[rev ? linearization.size() - 1 - i : i];1975// Construct a new group containing just idx. In even passes, the meaning of1976// parent/child and high/low feerate are swapped.1977DepGraphIndex cur_group = idx + 1;1978entries[cur_group].group = SetType::Singleton(idx);1979entries[cur_group].deps = rev ? depgraph.Descendants(idx): depgraph.Ancestors(idx);1980entries[cur_group].feerate = depgraph.FeeRate(idx);1981if (rev) entries[cur_group].feerate.fee = -entries[cur_group].feerate.fee;1982entries[cur_group].prev_tx = NO_PREV_TX; // No previous transaction in group.1983entries[cur_group].first_tx = cur_group; // Transaction itself is first of group.1984// Insert the new group at the back of the groups linked list.1985entries[cur_group].prev_group = entries[SENTINEL].prev_group;1986entries[SENTINEL].prev_group = cur_group;1988// Start merge/swap cycle.1989DepGraphIndex next_group = SENTINEL; // We inserted at the end, so next group is sentinel.1990DepGraphIndex prev_group = entries[cur_group].prev_group;1991// Continue as long as the current group has higher feerate than the previous one.1992while (ByRatio{entries[cur_group].feerate} > ByRatio{entries[prev_group].feerate}) {1993// prev_group/cur_group/next_group refer to (the last transactions of) 31994// consecutive entries in groups list.1995Assume(cur_group == entries[next_group].prev_group);1996Assume(prev_group == entries[cur_group].prev_group);1997// The sentinel has empty feerate, which is neither higher or lower than other1998// feerates. Thus, the while loop we are in here guarantees that cur_group and1999// prev_group are not the sentinel.2000Assume(cur_group != SENTINEL);
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.