txgraph: Add ability to configure maximum cluster size/weight (feature)

This is integrated with the oversized property: the graph is oversized when
any connected component within it contains more than the cluster count limit
many transactions, or when their combined size/weight exceeds the cluster size
limit.

It becomes disallowed to call AddTransaction with a size larger than this limit,
though this limit will be lifted in the next commit.

In addition, SetTransactionFeeRate becomes SetTransactionFee, so that we do not
need to deal with the case that a call to this function might affect the
oversizedness.
This commit is contained in:
Pieter Wuille
2024-12-17 08:13:25 -05:00
parent a92e8b10a5
commit c4287b9b71
3 changed files with 68 additions and 25 deletions

View File

@@ -109,6 +109,8 @@ public:
}
/** Get the number of transactions in this Cluster. */
LinearizationIndex GetTxCount() const noexcept { return m_linearization.size(); }
/** Get the total size of the transactions in this Cluster. */
uint64_t GetTotalTxSize() const noexcept;
/** Given a DepGraphIndex into this Cluster, find the corresponding GraphIndex. */
GraphIndex GetClusterEntry(DepGraphIndex index) const noexcept { return m_mapping[index]; }
/** Only called by Graph::SwapIndexes. */
@@ -199,6 +201,8 @@ private:
FastRandomContext m_rng;
/** This TxGraphImpl's maximum cluster count limit. */
const DepGraphIndex m_max_cluster_count;
/** This TxGraphImpl's maximum cluster size limit. */
const uint64_t m_max_cluster_size;
/** Information about one group of Clusters to be merged. */
struct GroupEntry
@@ -401,9 +405,10 @@ private:
std::vector<GraphIndex> m_unlinked;
public:
/** Construct a new TxGraphImpl with the specified maximum cluster count. */
explicit TxGraphImpl(DepGraphIndex max_cluster_count) noexcept :
/** Construct a new TxGraphImpl with the specified limits. */
explicit TxGraphImpl(DepGraphIndex max_cluster_count, uint64_t max_cluster_size) noexcept :
m_max_cluster_count(max_cluster_count),
m_max_cluster_size(max_cluster_size),
m_main_chunkindex(ChunkOrder(this))
{
Assume(max_cluster_count >= 1);
@@ -635,6 +640,15 @@ void TxGraphImpl::CreateChunkData(GraphIndex idx, LinearizationIndex chunk_count
}
}
uint64_t Cluster::GetTotalTxSize() const noexcept
{
uint64_t ret{0};
for (auto i : m_linearization) {
ret += m_depgraph.FeeRate(i).size;
}
return ret;
}
void TxGraphImpl::ClearLocator(int level, GraphIndex idx) noexcept
{
auto& entry = m_entries[idx];
@@ -1439,10 +1453,12 @@ void TxGraphImpl::GroupClusters(int level) noexcept
new_entry.m_deps_offset = clusterset.m_deps_to_add.size();
new_entry.m_deps_count = 0;
uint32_t total_count{0};
uint64_t total_size{0};
// Add all its clusters to it (copying those from an_clusters to m_group_clusters).
while (an_clusters_it != an_clusters.end() && an_clusters_it->second == rep) {
clusterset.m_group_data->m_group_clusters.push_back(an_clusters_it->first);
total_count += an_clusters_it->first->GetTxCount();
total_size += an_clusters_it->first->GetTotalTxSize();
++an_clusters_it;
++new_entry.m_cluster_count;
}
@@ -1453,7 +1469,7 @@ void TxGraphImpl::GroupClusters(int level) noexcept
++new_entry.m_deps_count;
}
// Detect oversizedness.
if (total_count > m_max_cluster_count) {
if (total_count > m_max_cluster_count || total_size > m_max_cluster_size) {
clusterset.m_group_data->m_group_oversized = true;
}
}
@@ -1587,6 +1603,7 @@ Cluster::Cluster(uint64_t sequence, TxGraphImpl& graph, const FeePerWeight& feer
TxGraph::Ref TxGraphImpl::AddTransaction(const FeePerWeight& feerate) noexcept
{
Assume(m_main_chunkindex_observers == 0 || GetTopLevel() != 0);
Assume(feerate.size > 0 && uint64_t(feerate.size) <= m_max_cluster_size);
// Construct a new Ref.
Ref ret;
// Construct a new Entry, and link it with the Ref.
@@ -2124,6 +2141,10 @@ void Cluster::SanityCheck(const TxGraphImpl& graph, int level) const
assert(m_linearization.size() <= graph.m_max_cluster_count);
// The level must match the level the Cluster occurs in.
assert(m_level == level);
// The sum of their sizes cannot exceed m_max_cluster_size. Note that groups of to-be-merged
// clusters which would exceed this limit are marked oversized, which means they are never
// applied.
assert(GetTotalTxSize() <= graph.m_max_cluster_size);
// m_quality and m_setindex are checked in TxGraphImpl::SanityCheck.
// Compute the chunking of m_linearization.
@@ -2500,7 +2521,7 @@ TxGraph::Ref::Ref(Ref&& other) noexcept
std::swap(m_index, other.m_index);
}
std::unique_ptr<TxGraph> MakeTxGraph(unsigned max_cluster_count) noexcept
std::unique_ptr<TxGraph> MakeTxGraph(unsigned max_cluster_count, uint64_t max_cluster_size) noexcept
{
return std::make_unique<TxGraphImpl>(max_cluster_count);
return std::make_unique<TxGraphImpl>(max_cluster_count, max_cluster_size);
}