aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bitcoin-chainstate.cpp2
-rw-r--r--src/init.cpp22
-rw-r--r--src/kernel/blockmanager_opts.h1
-rw-r--r--src/node/blockmanager_args.cpp2
-rw-r--r--src/node/blockstorage.cpp6
-rw-r--r--src/node/blockstorage.h14
-rw-r--r--src/node/chainstate.cpp20
-rw-r--r--src/node/chainstate.h9
-rw-r--r--src/test/util/setup_common.cpp4
-rw-r--r--src/validation.cpp31
-rwxr-xr-xtest/functional/feature_reindex.py20
-rwxr-xr-xtest/functional/test_framework/test_node.py4
12 files changed, 73 insertions, 62 deletions
diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp
index 4d2a6f0c2a..ca4434a882 100644
--- a/src/bitcoin-chainstate.cpp
+++ b/src/bitcoin-chainstate.cpp
@@ -151,7 +151,7 @@ int main(int argc, char* argv[])
{
LOCK(chainman.GetMutex());
std::cout
- << "\t" << "Reindexing: " << std::boolalpha << chainman.m_blockman.m_reindexing.load() << std::noboolalpha << std::endl
+ << "\t" << "Blockfiles Indexed: " << std::boolalpha << chainman.m_blockman.m_blockfiles_indexed.load() << std::noboolalpha << std::endl
<< "\t" << "Snapshot Active: " << std::boolalpha << chainman.IsSnapshotActive() << std::noboolalpha << std::endl
<< "\t" << "Active Height: " << chainman.ActiveHeight() << std::endl
<< "\t" << "Active IBD: " << std::boolalpha << chainman.IsInitialBlockDownload() << std::noboolalpha << std::endl;
diff --git a/src/init.cpp b/src/init.cpp
index 0aac2ac65f..253c8b7582 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1482,7 +1482,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
node.notifications = std::make_unique<KernelNotifications>(*Assert(node.shutdown), node.exit_status);
ReadNotificationArgs(args, *node.notifications);
- bool fReindexChainState = args.GetBoolArg("-reindex-chainstate", false);
ChainstateManager::Options chainman_opts{
.chainparams = chainparams,
.datadir = args.GetDataDirNet(),
@@ -1531,6 +1530,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
}
LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", cache_sizes.coins * (1.0 / 1024 / 1024), mempool_opts.max_size_bytes * (1.0 / 1024 / 1024));
+ bool do_reindex{args.GetBoolArg("-reindex", false)};
+ const bool do_reindex_chainstate{args.GetBoolArg("-reindex-chainstate", false)};
+
for (bool fLoaded = false; !fLoaded && !ShutdownRequested(node);) {
node.mempool = std::make_unique<CTxMemPool>(mempool_opts);
@@ -1558,8 +1560,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
node::ChainstateLoadOptions options;
options.mempool = Assert(node.mempool.get());
- options.reindex = chainman.m_blockman.m_reindexing;
- options.reindex_chainstate = fReindexChainState;
+ options.wipe_block_tree_db = do_reindex;
+ options.wipe_chainstate_db = do_reindex || do_reindex_chainstate;
options.prune = chainman.m_blockman.IsPruneMode();
options.check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
options.check_level = args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL);
@@ -1600,13 +1602,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
if (!fLoaded && !ShutdownRequested(node)) {
// first suggest a reindex
- if (!options.reindex) {
+ if (!do_reindex) {
bool fRet = uiInterface.ThreadSafeQuestion(
error + Untranslated(".\n\n") + _("Do you want to rebuild the block database now?"),
error.original + ".\nPlease restart with -reindex or -reindex-chainstate to recover.",
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);
if (fRet) {
- chainman.m_blockman.m_reindexing = true;
+ do_reindex = true;
if (!Assert(node.shutdown)->reset()) {
LogPrintf("Internal error: failed to reset shutdown signal.\n");
}
@@ -1639,17 +1641,17 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// ********************************************************* Step 8: start indexers
if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
- g_txindex = std::make_unique<TxIndex>(interfaces::MakeChain(node), cache_sizes.tx_index, false, chainman.m_blockman.m_reindexing);
+ g_txindex = std::make_unique<TxIndex>(interfaces::MakeChain(node), cache_sizes.tx_index, false, do_reindex);
node.indexes.emplace_back(g_txindex.get());
}
for (const auto& filter_type : g_enabled_filter_types) {
- InitBlockFilterIndex([&]{ return interfaces::MakeChain(node); }, filter_type, cache_sizes.filter_index, false, chainman.m_blockman.m_reindexing);
+ InitBlockFilterIndex([&]{ return interfaces::MakeChain(node); }, filter_type, cache_sizes.filter_index, false, do_reindex);
node.indexes.emplace_back(GetBlockFilterIndex(filter_type));
}
if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) {
- g_coin_stats_index = std::make_unique<CoinStatsIndex>(interfaces::MakeChain(node), /*cache_size=*/0, false, chainman.m_blockman.m_reindexing);
+ g_coin_stats_index = std::make_unique<CoinStatsIndex>(interfaces::MakeChain(node), /*cache_size=*/0, false, do_reindex);
node.indexes.emplace_back(g_coin_stats_index.get());
}
@@ -1668,7 +1670,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// if pruning, perform the initial blockstore prune
// after any wallet rescanning has taken place.
if (chainman.m_blockman.IsPruneMode()) {
- if (!chainman.m_blockman.m_reindexing) {
+ if (chainman.m_blockman.m_blockfiles_indexed) {
LOCK(cs_main);
for (Chainstate* chainstate : chainman.GetAll()) {
uiInterface.InitMessage(_("Pruning blockstoreā€¦").translated);
@@ -1694,7 +1696,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
int chain_active_height = WITH_LOCK(cs_main, return chainman.ActiveChain().Height());
// On first startup, warn on low block storage space
- if (!chainman.m_blockman.m_reindexing && !fReindexChainState && chain_active_height <= 1) {
+ if (!do_reindex && !do_reindex_chainstate && chain_active_height <= 1) {
uint64_t assumed_chain_bytes{chainparams.AssumedBlockchainSize() * 1024 * 1024 * 1024};
uint64_t additional_bytes_needed{
chainman.m_blockman.IsPruneMode() ?
diff --git a/src/kernel/blockmanager_opts.h b/src/kernel/blockmanager_opts.h
index 16072b669b..deeba7e318 100644
--- a/src/kernel/blockmanager_opts.h
+++ b/src/kernel/blockmanager_opts.h
@@ -24,7 +24,6 @@ struct BlockManagerOpts {
bool fast_prune{false};
const fs::path blocks_dir;
Notifications& notifications;
- bool reindex{false};
};
} // namespace kernel
diff --git a/src/node/blockmanager_args.cpp b/src/node/blockmanager_args.cpp
index dd8419a68a..fa76566652 100644
--- a/src/node/blockmanager_args.cpp
+++ b/src/node/blockmanager_args.cpp
@@ -33,8 +33,6 @@ util::Result<void> ApplyArgsManOptions(const ArgsManager& args, BlockManager::Op
if (auto value{args.GetBoolArg("-fastprune")}) opts.fast_prune = *value;
- if (auto value{args.GetBoolArg("-reindex")}) opts.reindex = *value;
-
return {};
}
} // namespace node
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index 4067ccee51..fb62e78138 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -551,7 +551,7 @@ bool BlockManager::LoadBlockIndexDB(const std::optional<uint256>& snapshot_block
// Check whether we need to continue reindexing
bool fReindexing = false;
m_block_tree_db->ReadReindexing(fReindexing);
- if (fReindexing) m_reindexing = true;
+ if (fReindexing) m_blockfiles_indexed = false;
return true;
}
@@ -1182,7 +1182,7 @@ void ImportBlocks(ChainstateManager& chainman, std::vector<fs::path> vImportFile
ImportingNow imp{chainman.m_blockman.m_importing};
// -reindex
- if (chainman.m_blockman.m_reindexing) {
+ if (!chainman.m_blockman.m_blockfiles_indexed) {
int nFile = 0;
// Map of disk positions for blocks with unknown parent (only used for reindex);
// parent hash -> child disk position, multiple children can have the same parent.
@@ -1205,7 +1205,7 @@ void ImportBlocks(ChainstateManager& chainman, std::vector<fs::path> vImportFile
nFile++;
}
WITH_LOCK(::cs_main, chainman.m_blockman.m_block_tree_db->WriteReindexing(false));
- chainman.m_blockman.m_reindexing = false;
+ chainman.m_blockman.m_blockfiles_indexed = true;
LogPrintf("Reindexing finished\n");
// To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked):
chainman.ActiveChainstate().LoadGenesisBlock();
diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h
index a501067091..108a08a72b 100644
--- a/src/node/blockstorage.h
+++ b/src/node/blockstorage.h
@@ -267,18 +267,18 @@ public:
explicit BlockManager(const util::SignalInterrupt& interrupt, Options opts)
: m_prune_mode{opts.prune_target > 0},
m_opts{std::move(opts)},
- m_interrupt{interrupt},
- m_reindexing{m_opts.reindex} {};
+ m_interrupt{interrupt} {}
const util::SignalInterrupt& m_interrupt;
std::atomic<bool> m_importing{false};
/**
- * Tracks if a reindex is currently in progress. Set to true when a reindex
- * is requested and false when reindexing completes. Its value is persisted
- * in the BlockTreeDB across restarts.
+ * Whether all blockfiles have been added to the block tree database.
+ * Normally true, but set to false when a reindex is requested and the
+ * database is wiped. The value is persisted in the database across restarts
+ * and will be false until reindexing completes.
*/
- std::atomic_bool m_reindexing;
+ std::atomic_bool m_blockfiles_indexed{true};
BlockMap m_block_index GUARDED_BY(cs_main);
@@ -359,7 +359,7 @@ public:
[[nodiscard]] uint64_t GetPruneTarget() const { return m_opts.prune_target; }
static constexpr auto PRUNE_TARGET_MANUAL{std::numeric_limits<uint64_t>::max()};
- [[nodiscard]] bool LoadingBlocks() const { return m_importing || m_reindexing; }
+ [[nodiscard]] bool LoadingBlocks() const { return m_importing || !m_blockfiles_indexed; }
/** Calculate the amount of disk space the block & undo files currently use */
uint64_t CalculateCurrentUsage();
diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp
index d6eb14f513..d7e6176be1 100644
--- a/src/node/chainstate.cpp
+++ b/src/node/chainstate.cpp
@@ -45,11 +45,12 @@ static ChainstateLoadResult CompleteChainstateInitialization(
.path = chainman.m_options.datadir / "blocks" / "index",
.cache_bytes = static_cast<size_t>(cache_sizes.block_tree_db),
.memory_only = options.block_tree_db_in_memory,
- .wipe_data = options.reindex,
+ .wipe_data = options.wipe_block_tree_db,
.options = chainman.m_options.block_tree_db});
- if (options.reindex) {
+ if (options.wipe_block_tree_db) {
pblocktree->WriteReindexing(true);
+ chainman.m_blockman.m_blockfiles_indexed = false;
//If we're reindexing in prune mode, wipe away unusable block files and all undo data files
if (options.prune) {
chainman.m_blockman.CleanupBlockRevFiles();
@@ -60,8 +61,7 @@ static ChainstateLoadResult CompleteChainstateInitialization(
// LoadBlockIndex will load m_have_pruned if we've ever removed a
// block file from disk.
- // Note that it also sets m_reindexing based on the disk flag!
- // From here on, m_reindexing and options.reindex values may be different!
+ // Note that it also sets m_blockfiles_indexed based on the disk flag!
if (!chainman.LoadBlockIndex()) {
if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};
return {ChainstateLoadStatus::FAILURE, _("Error loading block database")};
@@ -84,12 +84,12 @@ static ChainstateLoadResult CompleteChainstateInitialization(
// If we're not mid-reindex (based on disk + args), add a genesis block on disk
// (otherwise we use the one already on disk).
// This is called again in ImportBlocks after the reindex completes.
- if (!chainman.m_blockman.m_reindexing && !chainman.ActiveChainstate().LoadGenesisBlock()) {
+ if (chainman.m_blockman.m_blockfiles_indexed && !chainman.ActiveChainstate().LoadGenesisBlock()) {
return {ChainstateLoadStatus::FAILURE, _("Error initializing block database")};
}
auto is_coinsview_empty = [&](Chainstate* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
- return options.reindex || options.reindex_chainstate || chainstate->CoinsTip().GetBestBlock().IsNull();
+ return options.wipe_chainstate_db || chainstate->CoinsTip().GetBestBlock().IsNull();
};
assert(chainman.m_total_coinstip_cache > 0);
@@ -110,7 +110,7 @@ static ChainstateLoadResult CompleteChainstateInitialization(
chainstate->InitCoinsDB(
/*cache_size_bytes=*/chainman.m_total_coinsdb_cache * init_cache_fraction,
/*in_memory=*/options.coins_db_in_memory,
- /*should_wipe=*/options.reindex || options.reindex_chainstate);
+ /*should_wipe=*/options.wipe_chainstate_db);
if (options.coins_error_cb) {
chainstate->CoinsErrorCatcher().AddReadErrCallback(options.coins_error_cb);
@@ -142,7 +142,7 @@ static ChainstateLoadResult CompleteChainstateInitialization(
}
}
- if (!options.reindex) {
+ if (!options.wipe_block_tree_db) {
auto chainstates{chainman.GetAll()};
if (std::any_of(chainstates.begin(), chainstates.end(),
[](const Chainstate* cs) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return cs->NeedsRedownload(); })) {
@@ -188,7 +188,7 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
// Load a chain created from a UTXO snapshot, if any exist.
bool has_snapshot = chainman.DetectSnapshotChainstate();
- if (has_snapshot && (options.reindex || options.reindex_chainstate)) {
+ if (has_snapshot && options.wipe_chainstate_db) {
LogPrintf("[snapshot] deleting snapshot chainstate due to reindexing\n");
if (!chainman.DeleteSnapshotChainstate()) {
return {ChainstateLoadStatus::FAILURE_FATAL, Untranslated("Couldn't remove snapshot chainstate.")};
@@ -247,7 +247,7 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const ChainstateLoadOptions& options)
{
auto is_coinsview_empty = [&](Chainstate* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
- return options.reindex || options.reindex_chainstate || chainstate->CoinsTip().GetBestBlock().IsNull();
+ return options.wipe_chainstate_db || chainstate->CoinsTip().GetBestBlock().IsNull();
};
LOCK(cs_main);
diff --git a/src/node/chainstate.h b/src/node/chainstate.h
index a6e9a0331b..bb0c4f2b87 100644
--- a/src/node/chainstate.h
+++ b/src/node/chainstate.h
@@ -22,8 +22,13 @@ struct ChainstateLoadOptions {
CTxMemPool* mempool{nullptr};
bool block_tree_db_in_memory{false};
bool coins_db_in_memory{false};
- bool reindex{false};
- bool reindex_chainstate{false};
+ // Whether to wipe the block tree database when loading it. If set, this
+ // will also set a reindexing flag so any existing block data files will be
+ // scanned and added to the database.
+ bool wipe_block_tree_db{false};
+ // Whether to wipe the chainstate database when loading it. If set, this
+ // will cause the chainstate database to be rebuilt starting from genesis.
+ bool wipe_chainstate_db{false};
bool prune{false};
//! Setting require_full_verification to true will require all checks at
//! check_level (below) to succeed for loading to succeed. Setting it to
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index fd07931716..b366e83dde 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -276,8 +276,8 @@ void ChainTestingSetup::LoadVerifyActivateChainstate()
options.mempool = Assert(m_node.mempool.get());
options.block_tree_db_in_memory = m_block_tree_db_in_memory;
options.coins_db_in_memory = m_coins_db_in_memory;
- options.reindex = chainman.m_blockman.m_reindexing;
- options.reindex_chainstate = m_args.GetBoolArg("-reindex-chainstate", false);
+ options.wipe_block_tree_db = m_args.GetBoolArg("-reindex", false);
+ options.wipe_chainstate_db = m_args.GetBoolArg("-reindex", false) || m_args.GetBoolArg("-reindex-chainstate", false);
options.prune = chainman.m_blockman.IsPruneMode();
options.check_blocks = m_args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
options.check_level = m_args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL);
diff --git a/src/validation.cpp b/src/validation.cpp
index cecee0e9a9..aafb5629f4 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -2700,7 +2700,7 @@ bool Chainstate::FlushStateToDisk(
CoinsCacheSizeState cache_state = GetCoinsCacheSizeState();
LOCK(m_blockman.cs_LastBlockFile);
- if (m_blockman.IsPruneMode() && (m_blockman.m_check_for_pruning || nManualPruneHeight > 0) && !m_chainman.m_blockman.m_reindexing) {
+ if (m_blockman.IsPruneMode() && (m_blockman.m_check_for_pruning || nManualPruneHeight > 0) && m_chainman.m_blockman.m_blockfiles_indexed) {
// make sure we don't prune above any of the prune locks bestblocks
// pruning is height-based
int last_prune{m_chain.Height()}; // last height we can prune
@@ -3313,10 +3313,10 @@ bool Chainstate::ActivateBestChainStep(BlockValidationState& state, CBlockIndex*
return true;
}
-static SynchronizationState GetSynchronizationState(bool init, bool reindexing)
+static SynchronizationState GetSynchronizationState(bool init, bool blockfiles_indexed)
{
if (!init) return SynchronizationState::POST_INIT;
- if (reindexing) return SynchronizationState::INIT_REINDEX;
+ if (!blockfiles_indexed) return SynchronizationState::INIT_REINDEX;
return SynchronizationState::INIT_DOWNLOAD;
}
@@ -3338,7 +3338,7 @@ static bool NotifyHeaderTip(ChainstateManager& chainman) LOCKS_EXCLUDED(cs_main)
}
// Send block tip changed notifications without cs_main
if (fNotify) {
- chainman.GetNotifications().headerTip(GetSynchronizationState(fInitialBlockDownload, chainman.m_blockman.m_reindexing), pindexHeader->nHeight, pindexHeader->nTime, false);
+ chainman.GetNotifications().headerTip(GetSynchronizationState(fInitialBlockDownload, chainman.m_blockman.m_blockfiles_indexed), pindexHeader->nHeight, pindexHeader->nTime, false);
}
return fNotify;
}
@@ -3457,7 +3457,7 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
}
// Always notify the UI if a new block tip was connected
- if (kernel::IsInterrupted(m_chainman.GetNotifications().blockTip(GetSynchronizationState(still_in_ibd, m_chainman.m_blockman.m_reindexing), *pindexNewTip))) {
+ if (kernel::IsInterrupted(m_chainman.GetNotifications().blockTip(GetSynchronizationState(still_in_ibd, m_chainman.m_blockman.m_blockfiles_indexed), *pindexNewTip))) {
// Just breaking and returning success for now. This could
// be changed to bubble up the kernel::Interrupted value to
// the caller so the caller could distinguish between
@@ -3683,7 +3683,7 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde
// parameter indicating the source of the tip change so hooks can
// distinguish user-initiated invalidateblock changes from other
// changes.
- (void)m_chainman.GetNotifications().blockTip(GetSynchronizationState(m_chainman.IsInitialBlockDownload(), m_chainman.m_blockman.m_reindexing), *to_mark_failed->pprev);
+ (void)m_chainman.GetNotifications().blockTip(GetSynchronizationState(m_chainman.IsInitialBlockDownload(), m_chainman.m_blockman.m_blockfiles_indexed), *to_mark_failed->pprev);
}
return true;
}
@@ -4322,7 +4322,7 @@ void ChainstateManager::ReportHeadersPresync(const arith_uint256& work, int64_t
m_last_presync_update = now;
}
bool initial_download = IsInitialBlockDownload();
- GetNotifications().headerTip(GetSynchronizationState(initial_download, m_blockman.m_reindexing), height, timestamp, /*presync=*/true);
+ GetNotifications().headerTip(GetSynchronizationState(initial_download, m_blockman.m_blockfiles_indexed), height, timestamp, /*presync=*/true);
if (initial_download) {
int64_t blocks_left{(NodeClock::now() - NodeSeconds{std::chrono::seconds{timestamp}}) / GetConsensus().PowTargetSpacing()};
blocks_left = std::max<int64_t>(0, blocks_left);
@@ -4849,8 +4849,7 @@ bool ChainstateManager::LoadBlockIndex()
{
AssertLockHeld(cs_main);
// Load block index from databases
- bool needs_init = m_blockman.m_reindexing;
- if (!m_blockman.m_reindexing) {
+ if (m_blockman.m_blockfiles_indexed) {
bool ret{m_blockman.LoadBlockIndexDB(SnapshotBlockhash())};
if (!ret) return false;
@@ -4881,18 +4880,6 @@ bool ChainstateManager::LoadBlockIndex()
if (pindex->IsValid(BLOCK_VALID_TREE) && (m_best_header == nullptr || CBlockIndexWorkComparator()(m_best_header, pindex)))
m_best_header = pindex;
}
-
- needs_init = m_blockman.m_block_index.empty();
- }
-
- if (needs_init) {
- // Everything here is for *new* reindex/DBs. Thus, though
- // LoadBlockIndexDB may have set m_reindexing if we shut down
- // mid-reindex previously, we don't check m_reindexing and
- // instead only check it prior to LoadBlockIndexDB to set
- // needs_init.
-
- LogPrintf("Initializing databases...\n");
}
return true;
}
@@ -5033,7 +5020,7 @@ void ChainstateManager::LoadExternalBlockFile(
}
}
- if (m_blockman.IsPruneMode() && !m_blockman.m_reindexing && pblock) {
+ if (m_blockman.IsPruneMode() && m_blockman.m_blockfiles_indexed && pblock) {
// must update the tip for pruning to work while importing with -loadblock.
// this is a tradeoff to conserve disk space at the expense of time
// spent updating the tip to be able to prune.
diff --git a/test/functional/feature_reindex.py b/test/functional/feature_reindex.py
index f0f32a61ab..835cd0c5cf 100755
--- a/test/functional/feature_reindex.py
+++ b/test/functional/feature_reindex.py
@@ -73,6 +73,25 @@ class ReindexTest(BitcoinTestFramework):
# All blocks should be accepted and processed.
assert_equal(self.nodes[0].getblockcount(), 12)
+ def continue_reindex_after_shutdown(self):
+ node = self.nodes[0]
+ self.generate(node, 1500)
+
+ # Restart node with reindex and stop reindex as soon as it starts reindexing
+ self.log.info("Restarting node while reindexing..")
+ node.stop_node()
+ with node.busy_wait_for_debug_log([b'initload thread start']):
+ node.start(['-blockfilterindex', '-reindex'])
+ node.wait_for_rpc_connection(wait_for_import=False)
+ node.stop_node()
+
+ # Start node without the reindex flag and verify it does not wipe the indexes data again
+ db_path = node.chain_path / 'indexes' / 'blockfilter' / 'basic' / 'db'
+ with node.assert_debug_log(expected_msgs=[f'Opening LevelDB in {db_path}'], unexpected_msgs=[f'Wiping LevelDB in {db_path}']):
+ node.start(['-blockfilterindex'])
+ node.wait_for_rpc_connection(wait_for_import=False)
+ node.stop_node()
+
def run_test(self):
self.reindex(False)
self.reindex(True)
@@ -80,6 +99,7 @@ class ReindexTest(BitcoinTestFramework):
self.reindex(True)
self.out_of_order()
+ self.continue_reindex_after_shutdown()
if __name__ == '__main__':
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index 94ae96312e..0ac0af27d5 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -241,7 +241,7 @@ class TestNode():
if self.start_perf:
self._start_perf()
- def wait_for_rpc_connection(self):
+ def wait_for_rpc_connection(self, *, wait_for_import=True):
"""Sets up an RPC connection to the bitcoind process. Returns False if unable to connect."""
# Poll at a rate of four times per second
poll_per_s = 4
@@ -263,7 +263,7 @@ class TestNode():
)
rpc.getblockcount()
# If the call to getblockcount() succeeds then the RPC connection is up
- if self.version_is_at_least(190000):
+ if self.version_is_at_least(190000) and wait_for_import:
# getmempoolinfo.loaded is available since commit
# bb8ae2c (version 0.19.0)
self.wait_until(lambda: rpc.getmempoolinfo()['loaded'])