@@ -56,9 +56,12 @@ struct SimTxGraph
56
56
/* * Which transactions have been modified in the graph since creation, either directly or by
57
57
* being in a cluster which includes modifications. Only relevant for the staging graph. */
58
58
SetType modified;
59
+ /* * The configured maximum total size of transactions per cluster. */
60
+ uint64_t max_cluster_size;
59
61
60
- /* * Construct a new SimTxGraph with the specified maximum cluster count. */
61
- explicit SimTxGraph (DepGraphIndex max_cluster) : max_cluster_count(max_cluster) {}
62
+ /* * Construct a new SimTxGraph with the specified maximum cluster count and size. */
63
+ explicit SimTxGraph (DepGraphIndex cluster_count, uint64_t cluster_size) :
64
+ max_cluster_count(cluster_count), max_cluster_size(cluster_size) {}
62
65
63
66
// Permit copying and moving.
64
67
SimTxGraph (const SimTxGraph&) noexcept = default ;
@@ -78,6 +81,9 @@ struct SimTxGraph
78
81
while (todo.Any ()) {
79
82
auto component = graph.FindConnectedComponent (todo);
80
83
if (component.Count () > max_cluster_count) oversized = true ;
84
+ uint64_t component_size{0 };
85
+ for (auto i : component) component_size += graph.FeeRate (i).size ;
86
+ if (component_size > max_cluster_size) oversized = true ;
81
87
todo -= component;
82
88
}
83
89
}
@@ -260,14 +266,21 @@ FUZZ_TARGET(txgraph)
260
266
/* * Variable used whenever an empty TxGraph::Ref is needed. */
261
267
TxGraph::Ref empty_ref;
262
268
263
- // Decide the maximum number of transactions per cluster we will use in this simulation.
264
- auto max_count = provider.ConsumeIntegralInRange <DepGraphIndex>(1 , MAX_CLUSTER_COUNT_LIMIT);
269
+ /* * The maximum number of transactions per (non-oversized) cluster we will use in this
270
+ * simulation. */
271
+ auto max_cluster_count = provider.ConsumeIntegralInRange <DepGraphIndex>(1 , MAX_CLUSTER_COUNT_LIMIT);
272
+ /* * The maximum total size of transactions in a cluster, which also makes it an upper bound
273
+ * on the individual size of a transaction (but this restriction will be lifted in a future
274
+ * commit). */
275
+ auto max_cluster_size = provider.ConsumeIntegralInRange <uint64_t >(1 , 0x3fffff * MAX_CLUSTER_COUNT_LIMIT);
276
+ /* * The maximum individual transaction size used in this test (not a TxGraph parameter). */
277
+ auto max_tx_size = std::min<uint64_t >(0x3fffff , max_cluster_size);
265
278
266
279
// Construct a real graph, and a vector of simulated graphs (main, and possibly staging).
267
- auto real = MakeTxGraph (max_count );
280
+ auto real = MakeTxGraph (max_cluster_count, max_cluster_size );
268
281
std::vector<SimTxGraph> sims;
269
282
sims.reserve (2 );
270
- sims.emplace_back (max_count );
283
+ sims.emplace_back (max_cluster_count, max_cluster_size );
271
284
272
285
/* * Struct encapsulating information about a BlockBuilder that's currently live. */
273
286
struct BlockBuilderData
@@ -391,12 +404,12 @@ FUZZ_TARGET(txgraph)
391
404
if (alt) {
392
405
// If alt is true, pick fee and size from the entire range.
393
406
fee = provider.ConsumeIntegralInRange <int64_t >(-0x8000000000000 , 0x7ffffffffffff );
394
- size = provider.ConsumeIntegralInRange <int32_t >(1 , 0x3fffff );
407
+ size = provider.ConsumeIntegralInRange <int32_t >(1 , max_tx_size );
395
408
} else {
396
409
// Otherwise, use smaller range which consume fewer fuzz input bytes, as just
397
410
// these are likely sufficient to trigger all interesting code paths already.
398
411
fee = provider.ConsumeIntegral <uint8_t >();
399
- size = provider.ConsumeIntegral < uint8_t >() + 1 ;
412
+ size = provider.ConsumeIntegralInRange < uint32_t >( 1 , std::min< uint32_t >( 0xff , max_tx_size)) ;
400
413
}
401
414
FeePerWeight feerate{fee, size};
402
415
// Create a real TxGraph::Ref.
@@ -534,7 +547,7 @@ FUZZ_TARGET(txgraph)
534
547
auto ref = pick_fn ();
535
548
auto result = alt ? real->GetDescendants (*ref, use_main)
536
549
: real->GetAncestors (*ref, use_main);
537
- assert (result.size () <= max_count );
550
+ assert (result.size () <= max_cluster_count );
538
551
auto result_set = sel_sim.MakeSet (result);
539
552
assert (result.size () == result_set.Count ());
540
553
auto expect_set = sel_sim.GetAncDesc (ref, alt);
@@ -567,16 +580,20 @@ FUZZ_TARGET(txgraph)
567
580
auto ref = pick_fn ();
568
581
auto result = real->GetCluster (*ref, use_main);
569
582
// Check cluster count limit.
570
- assert (result.size () <= max_count );
583
+ assert (result.size () <= max_cluster_count );
571
584
// Require the result to be topologically valid and not contain duplicates.
572
585
auto left = sel_sim.graph .Positions ();
586
+ uint64_t total_size{0 };
573
587
for (auto refptr : result) {
574
588
auto simpos = sel_sim.Find (refptr);
589
+ total_size += sel_sim.graph .FeeRate (simpos).size ;
575
590
assert (simpos != SimTxGraph::MISSING);
576
591
assert (left[simpos]);
577
592
left.Reset (simpos);
578
593
assert (!sel_sim.graph .Ancestors (simpos).Overlaps (left));
579
594
}
595
+ // Check cluster size limit.
596
+ assert (total_size <= max_cluster_size);
580
597
// Require the set to be connected.
581
598
auto result_set = sel_sim.MakeSet (result);
582
599
assert (sel_sim.graph .IsConnected (result_set));
@@ -941,28 +958,32 @@ FUZZ_TARGET(txgraph)
941
958
// Check its ancestors against simulation.
942
959
auto expect_anc = sim.graph .Ancestors (i);
943
960
auto anc = sim.MakeSet (real->GetAncestors (*sim.GetRef (i), main_only));
944
- assert (anc.Count () <= max_count );
961
+ assert (anc.Count () <= max_cluster_count );
945
962
assert (anc == expect_anc);
946
963
// Check its descendants against simulation.
947
964
auto expect_desc = sim.graph .Descendants (i);
948
965
auto desc = sim.MakeSet (real->GetDescendants (*sim.GetRef (i), main_only));
949
- assert (desc.Count () <= max_count );
966
+ assert (desc.Count () <= max_cluster_count );
950
967
assert (desc == expect_desc);
951
968
// Check the cluster the transaction is part of.
952
969
auto cluster = real->GetCluster (*sim.GetRef (i), main_only);
953
- assert (cluster.size () <= max_count );
970
+ assert (cluster.size () <= max_cluster_count );
954
971
assert (sim.MakeSet (cluster) == component);
955
972
// Check that the cluster is reported in a valid topological order (its
956
973
// linearization).
957
974
std::vector<DepGraphIndex> simlin;
958
975
SimTxGraph::SetType done;
976
+ uint64_t total_size{0 };
959
977
for (TxGraph::Ref* ptr : cluster) {
960
978
auto simpos = sim.Find (ptr);
961
979
assert (sim.graph .Descendants (simpos).IsSubsetOf (component - done));
962
980
done.Set (simpos);
963
981
assert (sim.graph .Ancestors (simpos).IsSubsetOf (done));
964
982
simlin.push_back (simpos);
983
+ total_size += sim.graph .FeeRate (simpos).size ;
965
984
}
985
+ // Check cluster size.
986
+ assert (total_size <= max_cluster_size);
966
987
// Construct a chunking object for the simulated graph, using the reported cluster
967
988
// linearization as ordering, and compare it against the reported chunk feerates.
968
989
if (sims.size () == 1 || main_only) {
0 commit comments