Skip to content

Commit 97844d9

Browse files
committed
index: Enable reindex-chainstate with active indexes
This is achieved by letting the index sync thread wait until reindex-chainstate is finished. This also disables the pruning check when reindexing the chainstate (which is incompatible with prune mode) because there would be no chain at this point in init.
1 parent 60bec3c commit 97844d9

File tree

7 files changed

+27
-30
lines changed

7 files changed

+27
-30
lines changed

src/index/base.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include <string>
2424
#include <utility>
2525

26+
using node::g_indexes_ready_to_sync;
27+
2628
constexpr uint8_t DB_BEST_BLOCK{'B'};
2729

2830
constexpr auto SYNC_LOG_INTERVAL{30s};
@@ -105,7 +107,9 @@ bool BaseIndex::Init()
105107
// datadir and an index enabled. If this is the case, indexation will happen solely
106108
// via `BlockConnected` signals until, possibly, the next restart.
107109
m_synced = m_best_block_index.load() == active_chain.Tip();
108-
if (!m_synced) {
110+
111+
// Skip pruning check if indexes are not ready to sync (because reindex-chainstate has wiped the chain).
112+
if (!m_synced && g_indexes_ready_to_sync) {
109113
bool prune_violation = false;
110114
if (!m_best_block_index) {
111115
// index is not built yet
@@ -161,6 +165,12 @@ static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev, CChain&
161165
void BaseIndex::ThreadSync()
162166
{
163167
SetSyscallSandboxPolicy(SyscallSandboxPolicy::TX_INDEX);
168+
// Wait for a possible reindex-chainstate to finish until continuing
169+
// with the index sync
170+
while (!g_indexes_ready_to_sync) {
171+
if (!m_interrupt.sleep_for(std::chrono::milliseconds(500))) return;
172+
}
173+
164174
const CBlockIndex* pindex = m_best_block_index.load();
165175
if (!m_synced) {
166176
std::chrono::steady_clock::time_point last_log_time{0s};

src/init.cpp

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ using node::CalculateCacheSizes;
123123
using node::DEFAULT_PERSIST_MEMPOOL;
124124
using node::DEFAULT_PRINTPRIORITY;
125125
using node::fReindex;
126+
using node::g_indexes_ready_to_sync;
126127
using node::LoadChainstate;
127128
using node::MempoolPath;
128129
using node::NodeContext;
@@ -456,7 +457,7 @@ void SetupServerArgs(ArgsManager& argsman)
456457
"Warning: Reverting this setting requires re-downloading the entire blockchain. "
457458
"(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >=%u = automatically prune block files to stay under the specified target size in MiB)", MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
458459
argsman.AddArg("-reindex", "Rebuild chain state and block index from the blk*.dat files on disk. This will also rebuild active optional indexes.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
459-
argsman.AddArg("-reindex-chainstate", "Rebuild chain state from the currently indexed blocks. When in pruning mode or if blocks on disk might be corrupted, use full -reindex instead. Deactivate all optional indexes before running this.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
460+
argsman.AddArg("-reindex-chainstate", "Rebuild chain state from the currently indexed blocks. When in pruning mode or if blocks on disk might be corrupted, use full -reindex instead.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
460461
argsman.AddArg("-settings=<file>", strprintf("Specify path to dynamic settings data file. Can be disabled with -nosettings. File is written at runtime and not meant to be edited by users (use %s instead for custom settings). Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME, BITCOIN_SETTINGS_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
461462
#if HAVE_SYSTEM
462463
argsman.AddArg("-startupnotify=<cmd>", "Execute command on startup.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -982,19 +983,6 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb
982983
if (args.GetIntArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) > 1)
983984
return InitError(Untranslated("Unknown rpcserialversion requested."));
984985

985-
if (args.GetBoolArg("-reindex-chainstate", false)) {
986-
// indexes that must be deactivated to prevent index corruption, see #24630
987-
if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) {
988-
return InitError(_("-reindex-chainstate option is not compatible with -coinstatsindex. Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes."));
989-
}
990-
if (g_enabled_filter_types.count(BlockFilterType::BASIC)) {
991-
return InitError(_("-reindex-chainstate option is not compatible with -blockfilterindex. Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes."));
992-
}
993-
if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
994-
return InitError(_("-reindex-chainstate option is not compatible with -txindex. Please temporarily disable txindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes."));
995-
}
996-
}
997-
998986
#if defined(USE_SYSCALL_SANDBOX)
999987
if (args.IsArgSet("-sandbox") && !args.IsArgNegated("-sandbox")) {
1000988
const std::string sandbox_arg{args.GetArg("-sandbox", "")};
@@ -1571,6 +1559,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
15711559
RegisterValidationInterface(node.peerman.get());
15721560

15731561
// ********************************************************* Step 8: start indexers
1562+
1563+
// If reindex-chainstate was specified, delay syncing indexes until ThreadImport has reindexed the chain
1564+
if (!fReindexChainState) g_indexes_ready_to_sync = true;
15741565
if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
15751566
if (const auto error{WITH_LOCK(cs_main, return CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db)))}) {
15761567
return InitError(*error);

src/node/blockstorage.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
namespace node {
2929
std::atomic_bool fReindex(false);
30+
std::atomic_bool g_indexes_ready_to_sync{false};
3031

3132
bool CBlockIndexWorkComparator::operator()(const CBlockIndex* pa, const CBlockIndex* pb) const
3233
{
@@ -940,5 +941,6 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile
940941
}
941942
} // End scope of ImportingNow
942943
chainman.ActiveChainstate().LoadMempool(mempool_path);
944+
g_indexes_ready_to_sync = true;
943945
}
944946
} // namespace node

src/node/blockstorage.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
4747
static constexpr size_t BLOCK_SERIALIZATION_HEADER_SIZE = CMessageHeader::MESSAGE_START_SIZE + sizeof(unsigned int);
4848

4949
extern std::atomic_bool fReindex;
50+
extern std::atomic_bool g_indexes_ready_to_sync;
5051

5152
// Because validation code takes pointers to the map's CBlockIndex objects, if
5253
// we ever switch to another associative container, we need to either use a

src/test/util/setup_common.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ BasicTestingSetup::BasicTestingSetup(const ChainType chainType, const std::vecto
155155
noui_connect();
156156
noui_connected = true;
157157
}
158+
node::g_indexes_ready_to_sync = true;
158159
}
159160

160161
BasicTestingSetup::~BasicTestingSetup()

test/functional/feature_coinstatsindex.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -231,18 +231,16 @@ def _test_coin_stats_index(self):
231231
self.log.info("Test that the index works with -reindex")
232232

233233
self.restart_node(1, extra_args=["-coinstatsindex", "-reindex"])
234+
self.sync_index_node()
234235
res11 = index_node.gettxoutsetinfo('muhash')
235236
assert_equal(res11, res10)
236237

237-
self.log.info("Test that -reindex-chainstate is disallowed with coinstatsindex")
238+
self.log.info("Test that the index works with -reindex-chainstate")
238239

239-
self.stop_node(1)
240-
self.nodes[1].assert_start_raises_init_error(
241-
expected_msg='Error: -reindex-chainstate option is not compatible with -coinstatsindex. '
242-
'Please temporarily disable coinstatsindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.',
243-
extra_args=['-coinstatsindex', '-reindex-chainstate'],
244-
)
245-
self.restart_node(1, extra_args=["-coinstatsindex"])
240+
self.restart_node(1, extra_args=["-coinstatsindex", "-reindex-chainstate"])
241+
self.sync_index_node()
242+
res12 = index_node.gettxoutsetinfo('muhash')
243+
assert_equal(res12, res10)
246244

247245
def _test_use_index_option(self):
248246
self.log.info("Test use_index option for nodes running the index")
@@ -261,6 +259,7 @@ def _test_reorg_index(self):
261259
index_node = self.nodes[1]
262260
reorg_blocks = self.generatetoaddress(index_node, 2, getnewdestination()[2])
263261
reorg_block = reorg_blocks[1]
262+
self.sync_index_node()
264263
res_invalid = index_node.gettxoutsetinfo('muhash')
265264
index_node.invalidateblock(reorg_blocks[0])
266265
assert_equal(index_node.gettxoutsetinfo('muhash')['height'], 110)

test/functional/p2p_blockfilters.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -255,13 +255,6 @@ def run_test(self):
255255
msg = "Error: Unknown -blockfilterindex value abc."
256256
self.nodes[0].assert_start_raises_init_error(expected_msg=msg)
257257

258-
self.log.info("Test -blockfilterindex with -reindex-chainstate raises an error")
259-
self.nodes[0].assert_start_raises_init_error(
260-
expected_msg='Error: -reindex-chainstate option is not compatible with -blockfilterindex. '
261-
'Please temporarily disable blockfilterindex while using -reindex-chainstate, or replace -reindex-chainstate with -reindex to fully rebuild all indexes.',
262-
extra_args=['-blockfilterindex', '-reindex-chainstate'],
263-
)
264-
265258
def compute_last_header(prev_header, hashes):
266259
"""Compute the last filter header from a starting header and a sequence of filter hashes."""
267260
header = ser_uint256(prev_header)

0 commit comments

Comments
 (0)