Try to reduce a chunk's size. Returns false if all chunks are minimal, true otherwise. */
| 1355 | |
| 1356 | /** Try to reduce a chunk's size. Returns false if all chunks are minimal, true otherwise. */ |
| 1357 | bool MinimizeStep() noexcept |
| 1358 | { |
| 1359 | // If the queue of potentially-non-minimal chunks is empty, we are done. |
| 1360 | if (m_nonminimal_chunks.empty()) return false; |
| 1361 | m_cost.MinimizeStepBegin(); |
| 1362 | // Pop an entry from the potentially-non-minimal chunk queue. |
| 1363 | auto [chunk_idx, pivot_idx, flags] = m_nonminimal_chunks.front(); |
| 1364 | m_nonminimal_chunks.pop_front(); |
| 1365 | auto& chunk_info = m_set_info[chunk_idx]; |
| 1366 | /** Whether to move the pivot down rather than up. */ |
| 1367 | bool move_pivot_down = flags & 1; |
| 1368 | /** Whether this is already the second stage. */ |
| 1369 | bool second_stage = flags & 2; |
| 1370 | |
| 1371 | // Find a random dependency whose top and bottom set feerates are equal, and which has |
| 1372 | // pivot in bottom set (if move_pivot_down) or in top set (if !move_pivot_down). |
| 1373 | std::pair<TxIdx, TxIdx> candidate_dep; |
| 1374 | uint64_t candidate_tiebreak{0}; |
| 1375 | bool have_any = false; |
| 1376 | // Iterate over all transactions. |
| 1377 | for (auto tx_idx : chunk_info.transactions) { |
| 1378 | const auto& tx_data = m_tx_data[tx_idx]; |
| 1379 | // Iterate over all active child dependencies of the transaction. |
| 1380 | for (auto child_idx : tx_data.active_children) { |
| 1381 | const auto& dep_top_info = m_set_info[tx_data.dep_top_idx[child_idx]]; |
| 1382 | // Skip if this dependency does not have equal top and bottom set feerates. Note |
| 1383 | // that the top cannot have higher feerate than the bottom, or OptimizeSteps would |
| 1384 | // have dealt with it. |
| 1385 | if (ByRatio{dep_top_info.feerate} < ByRatio{chunk_info.feerate}) continue; |
| 1386 | have_any = true; |
| 1387 | // Skip if this dependency does not have pivot in the right place. |
| 1388 | if (move_pivot_down == dep_top_info.transactions[pivot_idx]) continue; |
| 1389 | // Remember this as our chosen dependency if it has a better tiebreak. |
| 1390 | uint64_t tiebreak = m_rng.rand64() | 1; |
| 1391 | if (tiebreak > candidate_tiebreak) { |
| 1392 | candidate_tiebreak = tiebreak; |
| 1393 | candidate_dep = {tx_idx, child_idx}; |
| 1394 | } |
| 1395 | } |
| 1396 | } |
| 1397 | m_cost.MinimizeStepMid(/*num_txns=*/chunk_info.transactions.Count()); |
| 1398 | // If no dependencies have equal top and bottom set feerate, this chunk is minimal. |
| 1399 | if (!have_any) return true; |
| 1400 | // If all found dependencies have the pivot in the wrong place, try moving it in the other |
| 1401 | // direction. If this was the second stage already, we are done. |
| 1402 | if (candidate_tiebreak == 0) { |
| 1403 | // Switch to other direction, and to second phase. |
| 1404 | flags ^= 3; |
| 1405 | if (!second_stage) m_nonminimal_chunks.emplace_back(chunk_idx, pivot_idx, flags); |
| 1406 | return true; |
| 1407 | } |
| 1408 | |
| 1409 | // Otherwise, deactivate the dependency that was found. |
| 1410 | auto [parent_chunk_idx, child_chunk_idx] = Deactivate(candidate_dep.first, candidate_dep.second); |
| 1411 | // Determine if there is a dependency from the new bottom to the new top (opposite from the |
| 1412 | // dependency that was just deactivated). |
| 1413 | auto& parent_reachable = m_reachable[parent_chunk_idx].first; |
| 1414 | auto& child_chunk_txn = m_set_info[child_chunk_idx].transactions; |