@@ -106,6 +106,12 @@ const std::vector<std::string> CHECKLEVEL_DOC {
106106 " level 4 tries to reconnect the blocks" ,
107107 " each level includes the checks of the previous levels" ,
108108};
109+ /* * The number of blocks to keep below the deepest prune lock.
110+ * There is nothing special about this number. It is higher than what we
111+ * expect to see in regular mainnet reorgs, but not so high that it would
112+ * noticeably interfere with the pruning mechanism.
113+ * */
114+ static constexpr int PRUNE_LOCK_BUFFER{10 };
109115
110116/* *
111117 * Mutex to guard access to validation specific variables, such as reading
@@ -2338,13 +2344,29 @@ bool CChainState::FlushStateToDisk(
23382344 CoinsCacheSizeState cache_state = GetCoinsCacheSizeState ();
23392345 LOCK (m_blockman.cs_LastBlockFile );
23402346 if (fPruneMode && (m_blockman.m_check_for_pruning || nManualPruneHeight > 0 ) && !fReindex ) {
2341- // make sure we don't prune above the blockfilterindexes bestblocks
2347+ // make sure we don't prune above any of the prune locks bestblocks
23422348 // pruning is height-based
2343- int last_prune = m_chain.Height (); // last height we can prune
2349+ int last_prune{m_chain.Height ()}; // last height we can prune
2350+ std::optional<std::string> limiting_lock; // prune lock that actually was the limiting factor, only used for logging
2351+
23442352 ForEachBlockFilterIndex ([&](BlockFilterIndex& index) {
2345- last_prune = std::max (1 , std::min (last_prune, index.GetSummary ().best_block_height ));
2353+ last_prune = std::max (1 , std::min (last_prune, index.GetSummary ().best_block_height ));
23462354 });
23472355
2356+ for (const auto & prune_lock : m_blockman.m_prune_locks ) {
2357+ if (prune_lock.second .height_first == std::numeric_limits<int >::max ()) continue ;
2358+ // Remove the buffer and one additional block here to get actual height that is outside of the buffer
2359+ const int lock_height{prune_lock.second .height_first - PRUNE_LOCK_BUFFER - 1 };
2360+ last_prune = std::max (1 , std::min (last_prune, lock_height));
2361+ if (last_prune == lock_height) {
2362+ limiting_lock = prune_lock.first ;
2363+ }
2364+ }
2365+
2366+ if (limiting_lock) {
2367+ LogPrint (BCLog::PRUNE, " %s limited pruning to height %d\n " , limiting_lock.value (), last_prune);
2368+ }
2369+
23482370 if (nManualPruneHeight > 0 ) {
23492371 LOG_TIME_MILLIS_WITH_CATEGORY (" find files to prune (manual)" , BCLog::BENCH);
23502372
@@ -2581,6 +2603,18 @@ bool CChainState::DisconnectTip(BlockValidationState& state, DisconnectedBlockTr
25812603 assert (flushed);
25822604 }
25832605 LogPrint (BCLog::BENCH, " - Disconnect block: %.2fms\n " , (GetTimeMicros () - nStart) * MILLI);
2606+
2607+ {
2608+ // Prune locks that began at or after the tip should be moved backward so they get a chance to reorg
2609+ const int max_height_first{pindexDelete->nHeight - 1 };
2610+ for (auto & prune_lock : m_blockman.m_prune_locks ) {
2611+ if (prune_lock.second .height_first <= max_height_first) continue ;
2612+
2613+ prune_lock.second .height_first = max_height_first;
2614+ LogPrint (BCLog::PRUNE, " %s prune lock moved back to %d\n " , prune_lock.first , max_height_first);
2615+ }
2616+ }
2617+
25842618 // Write the chain state to disk, if necessary.
25852619 if (!FlushStateToDisk (state, FlushStateMode::IF_NEEDED)) {
25862620 return false ;
0 commit comments