| 2834 | } |
| 2835 | |
| 2836 | void GenericClusterImpl::SanityCheck(const TxGraphImpl& graph, int level) const |
| 2837 | { |
| 2838 | // There must be an m_mapping for each m_depgraph position (including holes). |
| 2839 | assert(m_depgraph.PositionRange() == m_mapping.size()); |
| 2840 | // The linearization for this Cluster must contain every transaction once. |
| 2841 | assert(m_depgraph.TxCount() == m_linearization.size()); |
| 2842 | // Unless a split is to be applied, the cluster cannot have any holes. |
| 2843 | if (!NeedsSplitting()) { |
| 2844 | assert(m_depgraph.Positions() == SetType::Fill(m_depgraph.TxCount())); |
| 2845 | } |
| 2846 | |
| 2847 | // Compute the chunking of m_linearization. |
| 2848 | auto linchunking = ChunkLinearizationInfo(m_depgraph, m_linearization); |
| 2849 | unsigned chunk_num{0}; |
| 2850 | |
| 2851 | // Verify m_linearization. |
| 2852 | SetType m_done; |
| 2853 | LinearizationIndex linindex{0}; |
| 2854 | DepGraphIndex chunk_pos{0}; //!< position within the current chunk |
| 2855 | assert(m_depgraph.IsAcyclic()); |
| 2856 | if (m_linearization.empty()) return; |
| 2857 | FeeFrac equal_feerate_prefix = linchunking[chunk_num].feerate; |
| 2858 | for (auto lin_pos : m_linearization) { |
| 2859 | assert(lin_pos < m_mapping.size()); |
| 2860 | const auto& entry = graph.m_entries[m_mapping[lin_pos]]; |
| 2861 | // Check that the linearization is topological. |
| 2862 | m_done.Set(lin_pos); |
| 2863 | if (IsTopological()) { |
| 2864 | assert(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. |
| 2867 | assert(entry.m_locator[level].cluster == this); |
| 2868 | assert(entry.m_locator[level].index == lin_pos); |
| 2869 | // For main-level entries, check linearization position and chunk feerate. |
| 2870 | if (level == 0 && IsAcceptable()) { |
| 2871 | assert(entry.m_main_lin_index == linindex); |
| 2872 | ++linindex; |
| 2873 | if (!linchunking[chunk_num].transactions[lin_pos]) { |
| 2874 | // First transaction of a new chunk. |
| 2875 | ++chunk_num; |
| 2876 | assert(chunk_num < linchunking.size()); |
| 2877 | chunk_pos = 0; |
| 2878 | if (ByRatio{linchunking[chunk_num].feerate} < ByRatio{equal_feerate_prefix}) { |
| 2879 | equal_feerate_prefix = linchunking[chunk_num].feerate; |
| 2880 | } else { |
| 2881 | assert(ByRatio{linchunking[chunk_num].feerate} == ByRatio{equal_feerate_prefix}); |
| 2882 | equal_feerate_prefix += linchunking[chunk_num].feerate; |
| 2883 | } |
| 2884 | } |
| 2885 | assert(entry.m_main_chunk_feerate == linchunking[chunk_num].feerate); |
| 2886 | assert(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; |
| 2889 | if (graph.m_main_clusterset.m_to_remove.empty()) { |
| 2890 | bool is_chunk_end = (chunk_pos == linchunking[chunk_num].transactions.Count()); |
| 2891 | assert((entry.m_main_chunkindex_iterator != graph.m_main_chunkindex.end()) == is_chunk_end); |
| 2892 | if (is_chunk_end) { |
| 2893 | auto& chunk_data = *entry.m_main_chunkindex_iterator; |
nothing calls this directly
no test coverage detected