@@ -263,7 +263,7 @@ class TxGraphImpl final : public TxGraph
263
263
{
264
264
/* * The Entry which is the last transaction of the chunk. */
265
265
mutable GraphIndex m_graph_index;
266
- /* * How many transactions the chunk contains. */
266
+ /* * How many transactions the chunk contains (-1 = singleton tail of cluster) . */
267
267
LinearizationIndex m_chunk_count;
268
268
269
269
ChunkData (GraphIndex graph_index, LinearizationIndex chunk_count) noexcept :
@@ -681,7 +681,7 @@ void Cluster::Updated(TxGraphImpl& graph) noexcept
681
681
// Iterate over the chunks.
682
682
for (unsigned chunk_idx = 0 ; chunk_idx < chunking.NumChunksLeft (); ++chunk_idx) {
683
683
auto chunk = chunking.GetChunk (chunk_idx);
684
- const auto chunk_count = chunk.transactions .Count ();
684
+ auto chunk_count = chunk.transactions .Count ();
685
685
Assume (chunk_count > 0 );
686
686
// Iterate over the transactions in the linearization, which must match those in chunk.
687
687
while (true ) {
@@ -694,6 +694,12 @@ void Cluster::Updated(TxGraphImpl& graph) noexcept
694
694
chunk.transactions .Reset (idx);
695
695
if (chunk.transactions .None ()) {
696
696
// Last transaction in the chunk.
697
+ if (chunk_count == 1 && chunk_idx + 1 == chunking.NumChunksLeft ()) {
698
+ // If this is the final chunk of the cluster, and it contains just a single
699
+ // transaction (which will always be true for the very common singleton
700
+ // clusters), store the special value -1 as chunk count.
701
+ chunk_count = LinearizationIndex (-1 );
702
+ }
697
703
graph.CreateChunkData (graph_idx, chunk_count);
698
704
break ;
699
705
}
@@ -2152,7 +2158,11 @@ void Cluster::SanityCheck(const TxGraphImpl& graph, int level) const
2152
2158
assert ((entry.m_main_chunkindex_iterator != graph.m_main_chunkindex .end ()) == is_chunk_end);
2153
2159
if (is_chunk_end) {
2154
2160
auto & chunk_data = *entry.m_main_chunkindex_iterator ;
2155
- assert (chunk_data.m_chunk_count == chunk_pos);
2161
+ if (m_done == m_depgraph.Positions () && chunk_pos == 1 ) {
2162
+ assert (chunk_data.m_chunk_count == LinearizationIndex (-1 ));
2163
+ } else {
2164
+ assert (chunk_data.m_chunk_count == chunk_pos);
2165
+ }
2156
2166
}
2157
2167
// If this Cluster has an acceptable quality level, its chunks must be connected.
2158
2168
assert (m_depgraph.IsConnected (linchunking.GetChunk (0 ).transactions ));
@@ -2357,10 +2367,22 @@ std::optional<std::pair<std::vector<TxGraph::Ref*>, FeePerWeight>> BlockBuilderI
2357
2367
ret.emplace ();
2358
2368
const auto & chunk_data = *m_cur_iter;
2359
2369
const auto & chunk_end_entry = m_graph->m_entries [chunk_data.m_graph_index ];
2360
- ret->first .resize (chunk_data.m_chunk_count );
2361
- auto start_pos = chunk_end_entry.m_main_lin_index + 1 - chunk_data.m_chunk_count ;
2362
- Assume (m_cur_cluster);
2363
- m_known_end_of_cluster = m_cur_cluster->GetClusterRefs (*m_graph, ret->first , start_pos);
2370
+ if (chunk_data.m_chunk_count == LinearizationIndex (-1 )) {
2371
+ // Special case in case just a single transaction remains, avoiding the need to
2372
+ // dispatch to and dereference Cluster.
2373
+ ret->first .resize (1 );
2374
+ Assume (chunk_end_entry.m_ref != nullptr );
2375
+ ret->first [0 ] = chunk_end_entry.m_ref ;
2376
+ m_known_end_of_cluster = true ;
2377
+ } else {
2378
+ Assume (m_cur_cluster);
2379
+ ret->first .resize (chunk_data.m_chunk_count );
2380
+ auto start_pos = chunk_end_entry.m_main_lin_index + 1 - chunk_data.m_chunk_count ;
2381
+ m_known_end_of_cluster = m_cur_cluster->GetClusterRefs (*m_graph, ret->first , start_pos);
2382
+ // If the chunk size was 1 and at end of cluster, then the special case above should
2383
+ // have been used.
2384
+ Assume (!m_known_end_of_cluster || chunk_data.m_chunk_count > 1 );
2385
+ }
2364
2386
ret->second = chunk_end_entry.m_main_chunk_feerate ;
2365
2387
}
2366
2388
return ret;
@@ -2428,10 +2450,17 @@ std::pair<std::vector<TxGraph::Ref*>, FeePerWeight> TxGraphImpl::GetWorstMainChu
2428
2450
const auto & chunk_data = *m_main_chunkindex.rbegin ();
2429
2451
const auto & chunk_end_entry = m_entries[chunk_data.m_graph_index ];
2430
2452
Cluster* cluster = chunk_end_entry.m_locator [0 ].cluster ;
2431
- ret.first .resize (chunk_data.m_chunk_count );
2432
- auto start_pos = chunk_end_entry.m_main_lin_index + 1 - chunk_data.m_chunk_count ;
2433
- cluster->GetClusterRefs (*this , ret.first , start_pos);
2434
- std::reverse (ret.first .begin (), ret.first .end ());
2453
+ if (chunk_data.m_chunk_count == LinearizationIndex (-1 ) || chunk_data.m_chunk_count == 1 ) {
2454
+ // Special case for singletons.
2455
+ ret.first .resize (1 );
2456
+ Assume (chunk_end_entry.m_ref != nullptr );
2457
+ ret.first [0 ] = chunk_end_entry.m_ref ;
2458
+ } else {
2459
+ ret.first .resize (chunk_data.m_chunk_count );
2460
+ auto start_pos = chunk_end_entry.m_main_lin_index + 1 - chunk_data.m_chunk_count ;
2461
+ cluster->GetClusterRefs (*this , ret.first , start_pos);
2462
+ std::reverse (ret.first .begin (), ret.first .end ());
2463
+ }
2435
2464
ret.second = chunk_end_entry.m_main_chunk_feerate ;
2436
2465
}
2437
2466
return ret;
0 commit comments