mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 23:09:44 -04:00
clusterlin tests: support non-empty ReadTopologicalSubset()
In several call sites for ReadTopologicalSubset, a non-empty result is expected, necessitating a special case at the call site for empty results. Fix this by adding a bool non_empty argument, which does this special casing (more efficiently) inside ReadTopologicalSubset itself.
This commit is contained in:
parent
50a18d7143
commit
1d27b5b63b
1 changed files with 46 additions and 31 deletions
|
@ -184,12 +184,16 @@ void MakeConnected(DepGraph<BS>& depgraph)
|
||||||
|
|
||||||
/** Given a dependency graph, and a todo set, read a topological subset of todo from reader. */
|
/** Given a dependency graph, and a todo set, read a topological subset of todo from reader. */
|
||||||
template<typename SetType>
|
template<typename SetType>
|
||||||
SetType ReadTopologicalSet(const DepGraph<SetType>& depgraph, const SetType& todo, SpanReader& reader)
|
SetType ReadTopologicalSet(const DepGraph<SetType>& depgraph, const SetType& todo, SpanReader& reader, bool non_empty)
|
||||||
{
|
{
|
||||||
|
// Read a bitmask from the fuzzing input. Add 1 if non_empty, so the mask is definitely not
|
||||||
|
// zero in that case.
|
||||||
uint64_t mask{0};
|
uint64_t mask{0};
|
||||||
try {
|
try {
|
||||||
reader >> VARINT(mask);
|
reader >> VARINT(mask);
|
||||||
} catch(const std::ios_base::failure&) {}
|
} catch(const std::ios_base::failure&) {}
|
||||||
|
mask += non_empty;
|
||||||
|
|
||||||
SetType ret;
|
SetType ret;
|
||||||
for (auto i : todo) {
|
for (auto i : todo) {
|
||||||
if (!ret[i]) {
|
if (!ret[i]) {
|
||||||
|
@ -197,7 +201,17 @@ SetType ReadTopologicalSet(const DepGraph<SetType>& depgraph, const SetType& tod
|
||||||
mask >>= 1;
|
mask >>= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret & todo;
|
ret &= todo;
|
||||||
|
|
||||||
|
// While mask starts off non-zero if non_empty is true, it is still possible that all its low
|
||||||
|
// bits are 0, and ret ends up being empty. As a last resort, use the in-todo ancestry of the
|
||||||
|
// first todo position.
|
||||||
|
if (non_empty && ret.None()) {
|
||||||
|
Assume(todo.Any());
|
||||||
|
ret = depgraph.Ancestors(todo.First()) & todo;
|
||||||
|
Assume(ret.Any());
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Given a dependency graph, construct any valid linearization for it, reading from a SpanReader. */
|
/** Given a dependency graph, construct any valid linearization for it, reading from a SpanReader. */
|
||||||
|
@ -609,10 +623,10 @@ FUZZ_TARGET(clusterlin_ancestor_finder)
|
||||||
assert(real_best_anc.has_value());
|
assert(real_best_anc.has_value());
|
||||||
assert(*real_best_anc == best_anc);
|
assert(*real_best_anc == best_anc);
|
||||||
|
|
||||||
// Find a topologically valid subset of transactions to remove from the graph.
|
// Find a non-empty topologically valid subset of transactions to remove from the graph.
|
||||||
auto del_set = ReadTopologicalSet(depgraph, todo, reader);
|
// Using an empty set would mean the next iteration is identical to the current one, and
|
||||||
// If we did not find anything, use best_anc itself, because we should remove something.
|
// could cause an infinite loop.
|
||||||
if (del_set.None()) del_set = best_anc.transactions;
|
auto del_set = ReadTopologicalSet(depgraph, todo, reader, /*non_empty=*/true);
|
||||||
todo -= del_set;
|
todo -= del_set;
|
||||||
anc_finder.MarkDone(del_set);
|
anc_finder.MarkDone(del_set);
|
||||||
}
|
}
|
||||||
|
@ -688,15 +702,16 @@ FUZZ_TARGET(clusterlin_simple_finder)
|
||||||
assert(exhaustive.feerate == found.feerate);
|
assert(exhaustive.feerate == found.feerate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare with a topological set read from the fuzz input.
|
// Compare with a non-empty topological set read from the fuzz input (comparing with an
|
||||||
auto read_topo = ReadTopologicalSet(depgraph, todo, reader);
|
// empty set is not interesting).
|
||||||
if (read_topo.Any()) assert(found.feerate >= depgraph.FeeRate(read_topo));
|
auto read_topo = ReadTopologicalSet(depgraph, todo, reader, /*non_empty=*/true);
|
||||||
|
assert(found.feerate >= depgraph.FeeRate(read_topo));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find a topologically valid subset of transactions to remove from the graph.
|
// Find a non-empty topologically valid subset of transactions to remove from the graph.
|
||||||
auto del_set = ReadTopologicalSet(depgraph, todo, reader);
|
// Using an empty set would mean the next iteration is identical to the current one, and
|
||||||
// If we did not find anything, use found itself, because we should remove something.
|
// could cause an infinite loop.
|
||||||
if (del_set.None()) del_set = found.transactions;
|
auto del_set = ReadTopologicalSet(depgraph, todo, reader, /*non_empty=*/true);
|
||||||
todo -= del_set;
|
todo -= del_set;
|
||||||
smp_finder.MarkDone(del_set);
|
smp_finder.MarkDone(del_set);
|
||||||
exh_finder.MarkDone(del_set);
|
exh_finder.MarkDone(del_set);
|
||||||
|
@ -746,8 +761,9 @@ FUZZ_TARGET(clusterlin_search_finder)
|
||||||
} catch (const std::ios_base::failure&) {}
|
} catch (const std::ios_base::failure&) {}
|
||||||
max_iterations &= 0xfffff;
|
max_iterations &= 0xfffff;
|
||||||
|
|
||||||
// Read an initial subset from the fuzz input.
|
// Read an initial subset from the fuzz input (allowed to be empty).
|
||||||
SetInfo init_best(depgraph, ReadTopologicalSet(depgraph, todo, reader));
|
auto init_set = ReadTopologicalSet(depgraph, todo, reader, /*non_empty=*/false);
|
||||||
|
SetInfo init_best(depgraph, init_set);
|
||||||
|
|
||||||
// Call the search finder's FindCandidateSet for what remains of the graph.
|
// Call the search finder's FindCandidateSet for what remains of the graph.
|
||||||
auto [found, iterations_done] = src_finder.FindCandidateSet(max_iterations, init_best);
|
auto [found, iterations_done] = src_finder.FindCandidateSet(max_iterations, init_best);
|
||||||
|
@ -792,15 +808,16 @@ FUZZ_TARGET(clusterlin_search_finder)
|
||||||
auto anc = anc_finder.FindCandidateSet();
|
auto anc = anc_finder.FindCandidateSet();
|
||||||
assert(found.feerate >= anc.feerate);
|
assert(found.feerate >= anc.feerate);
|
||||||
|
|
||||||
// Compare with a topological set read from the fuzz input.
|
// Compare with a non-empty topological set read from the fuzz input (comparing with an
|
||||||
auto read_topo = ReadTopologicalSet(depgraph, todo, reader);
|
// empty set is not interesting).
|
||||||
if (read_topo.Any()) assert(found.feerate >= depgraph.FeeRate(read_topo));
|
auto read_topo = ReadTopologicalSet(depgraph, todo, reader, /*non_empty=*/true);
|
||||||
|
assert(found.feerate >= depgraph.FeeRate(read_topo));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find a topologically valid subset of transactions to remove from the graph.
|
// Find a non-empty topologically valid subset of transactions to remove from the graph.
|
||||||
auto del_set = ReadTopologicalSet(depgraph, todo, reader);
|
// Using an empty set would mean the next iteration is identical to the current one, and
|
||||||
// If we did not find anything, use found itself, because we should remove something.
|
// could cause an infinite loop.
|
||||||
if (del_set.None()) del_set = found.transactions;
|
auto del_set = ReadTopologicalSet(depgraph, todo, reader, /*non_empty=*/true);
|
||||||
todo -= del_set;
|
todo -= del_set;
|
||||||
src_finder.MarkDone(del_set);
|
src_finder.MarkDone(del_set);
|
||||||
smp_finder.MarkDone(del_set);
|
smp_finder.MarkDone(del_set);
|
||||||
|
@ -824,9 +841,10 @@ FUZZ_TARGET(clusterlin_linearization_chunking)
|
||||||
reader >> Using<DepGraphFormatter>(depgraph);
|
reader >> Using<DepGraphFormatter>(depgraph);
|
||||||
} catch (const std::ios_base::failure&) {}
|
} catch (const std::ios_base::failure&) {}
|
||||||
|
|
||||||
// Retrieve a topologically-valid subset of depgraph.
|
// Retrieve a topologically-valid subset of depgraph (allowed to be empty, because the argument
|
||||||
|
// to LinearizationChunking::Intersect is allowed to be empty).
|
||||||
auto todo = depgraph.Positions();
|
auto todo = depgraph.Positions();
|
||||||
auto subset = SetInfo(depgraph, ReadTopologicalSet(depgraph, todo, reader));
|
auto subset = SetInfo(depgraph, ReadTopologicalSet(depgraph, todo, reader, /*non_empty=*/false));
|
||||||
|
|
||||||
// Retrieve a valid linearization for depgraph.
|
// Retrieve a valid linearization for depgraph.
|
||||||
auto linearization = ReadLinearization(depgraph, reader);
|
auto linearization = ReadLinearization(depgraph, reader);
|
||||||
|
@ -915,13 +933,10 @@ FUZZ_TARGET(clusterlin_linearization_chunking)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find a subset to remove from linearization.
|
// Find a non-empty topologically valid subset of transactions to remove from the graph.
|
||||||
auto done = ReadTopologicalSet(depgraph, todo, reader);
|
// Using an empty set would mean the next iteration is identical to the current one, and
|
||||||
if (done.None()) {
|
// could cause an infinite loop.
|
||||||
// We need to remove a non-empty subset, so fall back to the unlinearized ancestors of
|
auto done = ReadTopologicalSet(depgraph, todo, reader, /*non_empty=*/true);
|
||||||
// the first transaction in todo if done is empty.
|
|
||||||
done = depgraph.Ancestors(todo.First()) & todo;
|
|
||||||
}
|
|
||||||
todo -= done;
|
todo -= done;
|
||||||
chunking.MarkDone(done);
|
chunking.MarkDone(done);
|
||||||
subset = SetInfo(depgraph, subset.transactions - done);
|
subset = SetInfo(depgraph, subset.transactions - done);
|
||||||
|
|
Loading…
Add table
Reference in a new issue