Skip to content

Commit 99b9022

Browse files
committed
Merge bitcoin/bitcoin#32177: TxGraph: Increase fuzz coverage
a40bd37 Get*Union: disallow nulltpr Refs (Greg Sanders) 5743350 CountDistinctClusters: nullptrs disallowed (Greg Sanders) 8bca0d3 TxGraphImpl::Compact: m_main_clusterset.m_removed is always empty (Greg Sanders) 2c5cf98 TxGraphImpl::PullIn: only allowed when staging exists (Greg Sanders) Pull request description: Was looking at my local coverage report, and noticed a few spots that will not or cannot be hit. CountDistinctClusters, GetAncestorsUnion, and GetDescendantsUnion accept nullptrs, but the test harness never employs them. Disallow them. We never call PullIn whenever there isn't staging, so just enforce that invariant via assertion. Remaining places that are not covered: 1) Relinearize: Currently we seem to always start with a cold (not known to be optimal) cluster, and after one attempt at linearization result into something optimal. This means we never shortcircuit, nor run PostLinearization, nor store the quality as ACCEPTABLE. Reducing iterations causes these lines to be hit. sipa says he will take this on as varying the amount of iterations was meant to be done eventually anyways. 2) We never do a move assignment operator when the lvalue already has a `m_graph` (so we never call UnlinkRef) https://github.com/bitcoin/bitcoin/blob/3358b1d105196647230e6f828b8ec820426b96a0/src/txgraph.cpp#L2097 3) We never use the move constructor: https://github.com/bitcoin/bitcoin/blob/3358b1d105196647230e6f828b8ec820426b96a0/src/txgraph.cpp#L2108 ACKs for top commit: sipa: utACK a40bd37 glozow: utACK a40bd37 Tree-SHA512: ca88297222e80e0d590889698899f892b9335cfa587a76a6c6ca62c8d846f208b6b0b9a9b1829bafabdb929a1a0c3a75f23edf7dd2b4f5e2dad0235e5bc68ba3
2 parents 639279e + a40bd37 commit 99b9022

File tree

2 files changed

+11
-9
lines changed

2 files changed

+11
-9
lines changed

src/txgraph.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -411,8 +411,8 @@ class TxGraphImpl final : public TxGraph
411411
* values for remaining Entry objects, so this only does something when no to-be-applied
412412
* operations or staged removals referring to GraphIndexes remain). */
413413
void Compact() noexcept;
414-
/** If cluster is not in staging, copy it there, and return a pointer to it. This has no
415-
* effect if only a main graph exists, but if staging exists this modifies the locators of its
414+
/** If cluster is not in staging, copy it there, and return a pointer to it.
415+
* Staging must exist, and this modifies the locators of its
416416
* transactions from inherited (P,M) to explicit (P,P). */
417417
Cluster* PullIn(Cluster* cluster) noexcept;
418418
/** Apply all removals queued up in m_to_remove to the relevant Clusters (which get a
@@ -928,7 +928,7 @@ Cluster* TxGraphImpl::FindCluster(GraphIndex idx, int level) const noexcept
928928
Cluster* TxGraphImpl::PullIn(Cluster* cluster) noexcept
929929
{
930930
int to_level = GetTopLevel();
931-
if (to_level == 0) return cluster;
931+
Assume(to_level == 1);
932932
int level = cluster->m_level;
933933
Assume(level <= to_level);
934934
// Copy the Cluster from main to staging, if it's not already there.
@@ -1008,7 +1008,7 @@ void TxGraphImpl::Compact() noexcept
10081008
// to rewrite them. It is easier to delay the compaction until they have been applied.
10091009
if (!m_main_clusterset.m_deps_to_add.empty()) return;
10101010
if (!m_main_clusterset.m_to_remove.empty()) return;
1011-
if (!m_main_clusterset.m_removed.empty()) return;
1011+
Assume(m_main_clusterset.m_removed.empty()); // non-staging m_removed is always empty
10121012
if (m_staging_clusterset.has_value()) {
10131013
if (!m_staging_clusterset->m_deps_to_add.empty()) return;
10141014
if (!m_staging_clusterset->m_to_remove.empty()) return;
@@ -1595,6 +1595,7 @@ std::vector<TxGraph::Ref*> TxGraphImpl::GetAncestorsUnion(std::span<const Ref* c
15951595
std::vector<std::pair<Cluster*, DepGraphIndex>> matches;
15961596
matches.reserve(args.size());
15971597
for (auto arg : args) {
1598+
Assume(arg);
15981599
// Skip empty Refs.
15991600
if (GetRefGraph(*arg) == nullptr) continue;
16001601
Assume(GetRefGraph(*arg) == this);
@@ -1627,6 +1628,7 @@ std::vector<TxGraph::Ref*> TxGraphImpl::GetDescendantsUnion(std::span<const Ref*
16271628
std::vector<std::pair<Cluster*, DepGraphIndex>> matches;
16281629
matches.reserve(args.size());
16291630
for (auto arg : args) {
1631+
Assume(arg);
16301632
// Skip empty Refs.
16311633
if (GetRefGraph(*arg) == nullptr) continue;
16321634
Assume(GetRefGraph(*arg) == this);
@@ -1880,7 +1882,7 @@ TxGraph::GraphIndex TxGraphImpl::CountDistinctClusters(std::span<const Ref* cons
18801882
std::vector<Cluster*> clusters;
18811883
clusters.reserve(refs.size());
18821884
for (const Ref* ref : refs) {
1883-
if (ref == nullptr) continue;
1885+
Assume(ref);
18841886
if (GetRefGraph(*ref) == nullptr) continue;
18851887
Assume(GetRefGraph(*ref) == this);
18861888
auto cluster = FindCluster(GetRefIndex(*ref), level);

src/txgraph.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,11 @@ class TxGraph
144144
virtual std::vector<Ref*> GetDescendants(const Ref& arg, bool main_only = false) noexcept = 0;
145145
/** Like GetAncestors, but return the Refs for all transactions in the union of the provided
146146
* arguments' ancestors (each transaction is only reported once). Refs that do not exist in
147-
* the queried graph are ignored. */
147+
* the queried graph are ignored. Null refs are not allowed. */
148148
virtual std::vector<Ref*> GetAncestorsUnion(std::span<const Ref* const> args, bool main_only = false) noexcept = 0;
149149
/** Like GetDescendants, but return the Refs for all transactions in the union of the provided
150150
* arguments' descendants (each transaction is only reported once). Refs that do not exist in
151-
* the queried graph are ignored. */
151+
* the queried graph are ignored. Null refs are not allowed. */
152152
virtual std::vector<Ref*> GetDescendantsUnion(std::span<const Ref* const> args, bool main_only = false) noexcept = 0;
153153
/** Get the total number of transactions in the graph. If main_only is false and a staging
154154
* graph exists, it is queried; otherwise the main graph is queried. This is available even
@@ -159,8 +159,8 @@ class TxGraph
159159
virtual std::strong_ordering CompareMainOrder(const Ref& a, const Ref& b) noexcept = 0;
160160
/** Count the number of distinct clusters that the specified transactions belong to. If
161161
* main_only is false and a staging graph exists, staging clusters are counted. Otherwise,
162-
* main clusters are counted. Refs that do not exist in the queried graph are ignored. The
163-
* queried graph must not be oversized. */
162+
* main clusters are counted. Refs that do not exist in the queried graph are ignored. Refs
163+
* can not be null. The queried graph must not be oversized. */
164164
virtual GraphIndex CountDistinctClusters(std::span<const Ref* const>, bool main_only = false) noexcept = 0;
165165

166166
/** Perform an internal consistency check on this object. */

0 commit comments

Comments
 (0)