@@ -158,6 +158,44 @@ SetType ReadTopologicalSet(const DepGraph<SetType>& depgraph, const SetType& tod
158158 return ret & todo;
159159}
160160
161+ /* * Given a dependency graph, construct any valid linearization for it, reading from a SpanReader. */
162+ template <typename BS>
163+ std::vector<ClusterIndex> ReadLinearization (const DepGraph<BS>& depgraph, SpanReader& reader)
164+ {
165+ std::vector<ClusterIndex> linearization;
166+ TestBitSet todo = TestBitSet::Fill (depgraph.TxCount ());
167+ // In every iteration one topologically-valid transaction is appended to linearization.
168+ while (todo.Any ()) {
169+ // Compute the set of transactions with no not-yet-included ancestors.
170+ TestBitSet potential_next;
171+ for (auto j : todo) {
172+ if ((depgraph.Ancestors (j) & todo) == TestBitSet::Singleton (j)) {
173+ potential_next.Set (j);
174+ }
175+ }
176+ // There must always be one (otherwise there is a cycle in the graph).
177+ assert (potential_next.Any ());
178+ // Read a number from reader, and interpret it as index into potential_next.
179+ uint64_t idx{0 };
180+ try {
181+ reader >> VARINT (idx);
182+ } catch (const std::ios_base::failure&) {}
183+ idx %= potential_next.Count ();
184+ // Find out which transaction that corresponds to.
185+ for (auto j : potential_next) {
186+ if (idx == 0 ) {
187+ // When found, add it to linearization and remove it from todo.
188+ linearization.push_back (j);
189+ assert (todo[j]);
190+ todo.Reset (j);
191+ break ;
192+ }
193+ --idx;
194+ }
195+ }
196+ return linearization;
197+ }
198+
161199} // namespace
162200
163201FUZZ_TARGET (clusterlin_add_dependency)
@@ -231,6 +269,48 @@ FUZZ_TARGET(clusterlin_depgraph_serialization)
231269 assert (IsAcyclic (depgraph));
232270}
233271
272+ FUZZ_TARGET (clusterlin_chunking)
273+ {
274+ // Verify the correctness of the ChunkLinearization function.
275+
276+ // Construct a graph by deserializing.
277+ SpanReader reader (buffer);
278+ DepGraph<TestBitSet> depgraph;
279+ try {
280+ reader >> Using<DepGraphFormatter>(depgraph);
281+ } catch (const std::ios_base::failure&) {}
282+
283+ // Read a valid linearization for depgraph.
284+ auto linearization = ReadLinearization (depgraph, reader);
285+
286+ // Invoke the chunking function.
287+ auto chunking = ChunkLinearization (depgraph, linearization);
288+
289+ // Verify that chunk feerates are monotonically non-increasing.
290+ for (size_t i = 1 ; i < chunking.size (); ++i) {
291+ assert (!(chunking[i] >> chunking[i - 1 ]));
292+ }
293+
294+ // Naively recompute the chunks (each is the highest-feerate prefix of what remains).
295+ auto todo = TestBitSet::Fill (depgraph.TxCount ());
296+ for (const auto & chunk_feerate : chunking) {
297+ assert (todo.Any ());
298+ SetInfo<TestBitSet> accumulator, best;
299+ for (ClusterIndex idx : linearization) {
300+ if (todo[idx]) {
301+ accumulator |= SetInfo (depgraph, idx);
302+ if (best.feerate .IsEmpty () || accumulator.feerate >> best.feerate ) {
303+ best = accumulator;
304+ }
305+ }
306+ }
307+ assert (chunk_feerate == best.feerate );
308+ assert (best.transactions .IsSubsetOf (todo));
309+ todo -= best.transactions ;
310+ }
311+ assert (todo.None ());
312+ }
313+
234314FUZZ_TARGET (clusterlin_ancestor_finder)
235315{
236316 // Verify that AncestorCandidateFinder works as expected.
0 commit comments