Skip to content

Commit 3a83d44

Browse files
committed
Merge bitcoin/bitcoin#27720: index: prevent race by calling 'CustomInit' prior setting 'synced' flag
3126454 index: prevent race by calling 'CustomInit' prior setting 'synced' flag (furszy) Pull request description: Decoupled from #27607. Fixed a potential race condition in master (not possible so far) that could become an actual issue soon. Where the index's `CustomAppend` method could be called (from `BlockConnected`) before its `CustomInit` method, causing the index to try to update itself before it is initialized. This could happen because we set the index `m_synced` flag (which enables `BlockConnected` events) before calling to the child class init function (`CustomInit`). So, for example, the block filter index could process a block before initialize the next filter position field and end up overwriting the first stored filter. This race was introduced in bitcoin/bitcoin@bef4e40 from bitcoin/bitcoin#25494. ACKs for top commit: achow101: ACK 3126454 mzumsande: Code review ACK 3126454 TheCharlatan: Nice, ACK 3126454 Tree-SHA512: 7a53fed1d2035cb4c1f331d6ee9f92d499b6cbb618ea534c6440f5a45ff9b3ac4dcff5fb4b88937f45a0be249e3a9c6dc6c3ac77180f12ae25fc56856ba39735
2 parents f08bde7 + 3126454 commit 3a83d44

File tree

1 file changed

+15
-13
lines changed

1 file changed

+15
-13
lines changed

src/index/base.cpp

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -103,23 +103,20 @@ bool BaseIndex::Init()
103103
SetBestBlockIndex(locator_index);
104104
}
105105

106-
// Note: this will latch to true immediately if the user starts up with an empty
107-
// datadir and an index enabled. If this is the case, indexation will happen solely
108-
// via `BlockConnected` signals until, possibly, the next restart.
109-
m_synced = m_best_block_index.load() == active_chain.Tip();
110-
111106
// 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) {
107+
const CBlockIndex* start_block = m_best_block_index.load();
108+
bool synced = start_block == active_chain.Tip();
109+
if (!synced && g_indexes_ready_to_sync) {
113110
bool prune_violation = false;
114-
if (!m_best_block_index) {
111+
if (!start_block) {
115112
// index is not built yet
116113
// make sure we have all block data back to the genesis
117114
prune_violation = m_chainstate->m_blockman.GetFirstStoredBlock(*active_chain.Tip()) != active_chain.Genesis();
118115
}
119116
// in case the index has a best block set and is not fully synced
120117
// check if we have the required blocks to continue building the index
121118
else {
122-
const CBlockIndex* block_to_test = m_best_block_index.load();
119+
const CBlockIndex* block_to_test = start_block;
123120
if (!active_chain.Contains(block_to_test)) {
124121
// if the bestblock is not part of the mainchain, find the fork
125122
// and make sure we have all data down to the fork
@@ -143,6 +140,16 @@ bool BaseIndex::Init()
143140
return InitError(strprintf(Untranslated("%s best block of the index goes beyond pruned data. Please disable the index or reindex (which will download the whole blockchain again)"), GetName()));
144141
}
145142
}
143+
144+
// Child init
145+
if (!CustomInit(start_block ? std::make_optional(interfaces::BlockKey{start_block->GetBlockHash(), start_block->nHeight}) : std::nullopt)) {
146+
return false;
147+
}
148+
149+
// Note: this will latch to true immediately if the user starts up with an empty
150+
// datadir and an index enabled. If this is the case, indexation will happen solely
151+
// via `BlockConnected` signals until, possibly, the next restart.
152+
m_synced = synced;
146153
return true;
147154
}
148155

@@ -408,11 +415,6 @@ bool BaseIndex::Start()
408415
RegisterValidationInterface(this);
409416
if (!Init()) return false;
410417

411-
const CBlockIndex* index = m_best_block_index.load();
412-
if (!CustomInit(index ? std::make_optional(interfaces::BlockKey{index->GetBlockHash(), index->nHeight}) : std::nullopt)) {
413-
return false;
414-
}
415-
416418
m_thread_sync = std::thread(&util::TraceThread, GetName(), [this] { ThreadSync(); });
417419
return true;
418420
}

0 commit comments

Comments
 (0)