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.
2751Assume(m_main_chunkindex_observers == 0);2752// Find the entry, its locator, and inform its Cluster about the new feerate, if any.2753auto& entry = m_entries[GetRefIndex(ref)];2754for (int level = 0; level < MAX_LEVELS; ++level) {2755auto& locator = entry.m_locator[level];2756if (locator.IsPresent()) {2757locator.cluster->SetFee(*this, level, locator.index, fee);2758}2759}2760}2762std::strong_ordering TxGraphImpl::CompareMainOrder(const Ref& a, const Ref& b) noexcept2763{2764// The references must not be empty.2765Assume(GetRefGraph(a) == this);2766Assume(GetRefGraph(b) == this);2767// Apply dependencies in main.2768ApplyDependencies(0);2769Assume(m_main_clusterset.m_deps_to_add.empty());2770// Make both involved Clusters acceptable, so chunk feerates are relevant.2771const auto& entry_a = m_entries[GetRefIndex(a)];2772const auto& entry_b = m_entries[GetRefIndex(b)];2773const auto& locator_a = entry_a.m_locator[0];2774const auto& locator_b = entry_b.m_locator[0];2775Assume(locator_a.IsPresent());2776Assume(locator_b.IsPresent());2777MakeAcceptable(*locator_a.cluster, /*level=*/0);2778MakeAcceptable(*locator_b.cluster, /*level=*/0);2779// Invoke comparison logic.2780return CompareMainTransactions(GetRefIndex(a), GetRefIndex(b));2781}2783TxGraph::GraphIndex TxGraphImpl::CountDistinctClusters(std::span<const Ref* const> refs, Level level_select) noexcept2784{2785size_t level = GetSpecifiedLevel(level_select);2786ApplyDependencies(level);2787auto& clusterset = GetClusterSet(level);2788Assume(clusterset.m_deps_to_add.empty());2789// Build a vector of Clusters that the specified Refs occur in.2790std::vector<Cluster*> clusters;2791clusters.reserve(refs.size());2792for (const Ref* ref : refs) {2793Assume(ref);2794if (GetRefGraph(*ref) == nullptr) continue;2795Assume(GetRefGraph(*ref) == this);2796auto cluster = FindCluster(GetRefIndex(*ref), level);2797if (cluster != nullptr) clusters.push_back(cluster);2798}2799// Count the number of distinct elements in clusters.2800std::ranges::sort(clusters, [](Cluster* a, Cluster* b) noexcept { return CompareClusters(a, b) < 0; });2801Cluster* last{nullptr};2802GraphIndex ret{0};2803for (Cluster* cluster : clusters) {2804ret += (cluster != last);2805last = cluster;2806}2807return ret;2808}2810std::pair<std::vector<FeeFrac>, std::vector<FeeFrac>> TxGraphImpl::GetMainStagingDiagrams() noexcept2811{2812Assume(m_staging_clusterset.has_value());2813MakeAllAcceptable(0);2814Assume(m_main_clusterset.m_deps_to_add.empty()); // can only fail if main is oversized2815MakeAllAcceptable(1);2816Assume(m_staging_clusterset->m_deps_to_add.empty()); // can only fail if staging is oversized2817// For all Clusters in main which conflict with Clusters in staging (i.e., all that are removed2818// by, or replaced in, staging), gather their chunk feerates.2819auto main_clusters = GetConflicts();2820std::vector<FeeFrac> main_feerates, staging_feerates;2821for (Cluster* cluster : main_clusters) {2822cluster->AppendChunkFeerates(main_feerates);2823}2824// Do the same for the Clusters in staging themselves.2825for (int quality = 0; quality < int(QualityLevel::NONE); ++quality) {2826for (const auto& cluster : m_staging_clusterset->m_clusters[quality]) {2827cluster->AppendChunkFeerates(staging_feerates);2828}2829}2830// Sort both by decreasing feerate to obtain diagrams, and return them.2831std::ranges::sort(main_feerates, std::greater<ByRatioNegSize<FeeFrac>>{});2832std::ranges::sort(staging_feerates, std::greater<ByRatioNegSize<FeeFrac>>{});2833return std::make_pair(std::move(main_feerates), std::move(staging_feerates));2834}2836void GenericClusterImpl::SanityCheck(const TxGraphImpl& graph, int level) const2837{2838// There must be an m_mapping for each m_depgraph position (including holes).2839assert(m_depgraph.PositionRange() == m_mapping.size());2840// The linearization for this Cluster must contain every transaction once.2841assert(m_depgraph.TxCount() == m_linearization.size());2842// Unless a split is to be applied, the cluster cannot have any holes.2843if (!NeedsSplitting()) {2844assert(m_depgraph.Positions() == SetType::Fill(m_depgraph.TxCount()));2845}2847// Compute the chunking of m_linearization.2848auto linchunking = ChunkLinearizationInfo(m_depgraph, m_linearization);2849unsigned chunk_num{0};2851// Verify m_linearization.2852SetType m_done;2853LinearizationIndex linindex{0};2854DepGraphIndex chunk_pos{0}; //!< position within the current chunk2855assert(m_depgraph.IsAcyclic());2856if (m_linearization.empty()) return;2857FeeFrac equal_feerate_prefix = linchunking[chunk_num].feerate;2858for (auto lin_pos : m_linearization) {2859assert(lin_pos < m_mapping.size());2860const auto& entry = graph.m_entries[m_mapping[lin_pos]];2861// Check that the linearization is topological.2862m_done.Set(lin_pos);2863if (IsTopological()) {2864assert(m_done.IsSupersetOf(m_depgraph.Ancestors(lin_pos)));2865}2866// Check that the Entry has a locator pointing back to this Cluster & position within it.2867assert(entry.m_locator[level].cluster == this);2868assert(entry.m_locator[level].index == lin_pos);2869// For main-level entries, check linearization position and chunk feerate.2870if (level == 0 && IsAcceptable()) {2871assert(entry.m_main_lin_index == linindex);2872++linindex;2873if (!linchunking[chunk_num].transactions[lin_pos]) {2874// First transaction of a new chunk.2875++chunk_num;2876assert(chunk_num < linchunking.size());2877chunk_pos = 0;2878if (ByRatio{linchunking[chunk_num].feerate} < ByRatio{equal_feerate_prefix}) {2879equal_feerate_prefix = linchunking[chunk_num].feerate;2880} else {2881assert(ByRatio{linchunking[chunk_num].feerate} == ByRatio{equal_feerate_prefix});2882equal_feerate_prefix += linchunking[chunk_num].feerate;2883}2884}2885assert(entry.m_main_chunk_feerate == linchunking[chunk_num].feerate);2886assert(entry.m_main_equal_feerate_chunk_prefix_size == equal_feerate_prefix.size);2887// Verify that an entry in the chunk index exists for every chunk-ending transaction.2888++chunk_pos;2889if (graph.m_main_clusterset.m_to_remove.empty()) {2890bool is_chunk_end = (chunk_pos == linchunking[chunk_num].transactions.Count());2891assert((entry.m_main_chunkindex_iterator != graph.m_main_chunkindex.end()) == is_chunk_end);2892if (is_chunk_end) {2893auto& chunk_data = *entry.m_main_chunkindex_iterator;2894if (m_done == m_depgraph.Positions() && chunk_pos == 1) {2895assert(chunk_data.m_chunk_count == LinearizationIndex(-1));2896} else {2897assert(chunk_data.m_chunk_count == chunk_pos);2898}2899}2900}2901// If this Cluster has an acceptable quality level, its chunks must be connected.2902assert(m_depgraph.IsConnected(linchunking[chunk_num].transactions));2903}2904}2905// Verify that each element of m_depgraph occurred in m_linearization.2906assert(m_done == m_depgraph.Positions());2907}2909void SingletonClusterImpl::SanityCheck(const TxGraphImpl& graph, int level) const2910{2911// All singletons are optimal, oversized, or need splitting.2912Assume(IsOptimal() || IsOversized() || NeedsSplitting());2913if (GetTxCount()) {2914const auto& entry = graph.m_entries[m_graph_index];2915// Check that the Entry has a locator pointing back to this Cluster & position within it.2916assert(entry.m_locator[level].cluster == this);2917assert(entry.m_locator[level].index == 0);2918// For main-level entries, check linearization position and chunk feerate.2919if (level == 0 && IsAcceptable()) {2920assert(entry.m_main_lin_index == 0);2921assert(entry.m_main_chunk_feerate == m_feerate);2922assert(entry.m_main_equal_feerate_chunk_prefix_size == m_feerate.size);2923if (graph.m_main_clusterset.m_to_remove.empty()) {2924assert(entry.m_main_chunkindex_iterator != graph.m_main_chunkindex.end());2925auto& chunk_data = *entry.m_main_chunkindex_iterator;2926assert(chunk_data.m_chunk_count == LinearizationIndex(-1));2927}2928}2929}2930}2932void TxGraphImpl::SanityCheck() const2933{2934/** Which GraphIndexes ought to occur in m_unlinked, based on m_entries. */2935std::set<GraphIndex> expected_unlinked;2936/** Which Clusters ought to occur in ClusterSet::m_clusters, based on m_entries. */2937std::set<const Cluster*> expected_clusters[MAX_LEVELS];2938/** Which GraphIndexes ought to occur in ClusterSet::m_removed, based on m_entries. */2939std::set<GraphIndex> expected_removed[MAX_LEVELS];2940/** Which Cluster::m_sequence values have been encountered. */2941std::set<uint64_t> sequences;2942/** Which Clusters are live in ClusterSet::m_clusters up to the level being checked. */2943std::set<const Cluster*> live_clusters;2944/** Which GraphIndexes ought to occur in m_main_chunkindex, based on m_entries. */2945std::set<GraphIndex> expected_chunkindex;2946/** Whether compaction is possible in the current state. */2947bool compact_possible{true};2949// Go over all Entry objects in m_entries.2950for (GraphIndex idx = 0; idx < m_entries.size(); ++idx) {2951const auto& entry = m_entries[idx];2952if (entry.m_ref == nullptr) {2953// Unlinked Entry must have indexes appear in m_unlinked.2954expected_unlinked.insert(idx);2955} else {2956// Every non-unlinked Entry must have a Ref that points back to it.2957assert(GetRefGraph(*entry.m_ref) == this);2958assert(GetRefIndex(*entry.m_ref) == idx);2959}2960if (entry.m_main_chunkindex_iterator != m_main_chunkindex.end()) {2961// Remember which entries we see a chunkindex entry for.2962assert(entry.m_locator[0].IsPresent());2963expected_chunkindex.insert(idx);2964}2965// Verify the Entry m_locators.2966bool was_present{false}, was_removed{false};2967for (int level = 0; level < MAX_LEVELS; ++level) {2968const auto& locator = entry.m_locator[level];2969// Every Locator must be in exactly one of these 3 states.2970assert(locator.IsMissing() + locator.IsRemoved() + locator.IsPresent() == 1);2971if (locator.IsPresent()) {2972// Once removed, a transaction cannot be revived.2973assert(!was_removed);2974// Verify that the Cluster agrees with where the Locator claims the transaction is.2975assert(locator.cluster->GetClusterEntry(locator.index) == idx);2976// Remember that we expect said Cluster to appear in the ClusterSet::m_clusters.2977expected_clusters[level].insert(locator.cluster);2978was_present = true;2979} else if (locator.IsRemoved()) {2980// Level 0 (main) cannot have IsRemoved locators (IsMissing there means non-existing).2981assert(level > 0);2982// A Locator can only be IsRemoved if it was IsPresent before, and only once.2983assert(was_present && !was_removed);2984// Remember that we expect this GraphIndex to occur in the ClusterSet::m_removed.2985expected_removed[level].insert(idx);2986was_removed = true;2987}2988}2989}2991// For all levels (0 = main, 1 = staged)...2992for (int level = 0; level <= GetTopLevel(); ++level) {2993assert(level < MAX_LEVELS);2994auto& clusterset = GetClusterSet(level);2995std::set<const Cluster*> actual_clusters;2996size_t recomputed_cluster_usage{0};2998// For all quality levels...2999for (int qual = 0; qual < int(QualityLevel::NONE); ++qual) {3000QualityLevel quality{qual};
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.