@@ -158,6 +158,44 @@ SetType ReadTopologicalSet(const DepGraph<SetType>& depgraph, const SetType& tod
158
158
return ret & todo;
159
159
}
160
160
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
+
161
199
} // namespace
162
200
163
201
FUZZ_TARGET (clusterlin_add_dependency)
@@ -231,6 +269,48 @@ FUZZ_TARGET(clusterlin_depgraph_serialization)
231
269
assert (IsAcyclic (depgraph));
232
270
}
233
271
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
+
234
314
FUZZ_TARGET (clusterlin_ancestor_finder)
235
315
{
236
316
// Verify that AncestorCandidateFinder works as expected.
0 commit comments