| 2360 | } |
| 2361 | |
| 2362 | bool StartIndexBackgroundSync(NodeContext& node) |
| 2363 | { |
| 2364 | ChainstateManager& chainman = *Assert(node.chainman); |
| 2365 | const Chainstate& chainstate = WITH_LOCK(::cs_main, return chainman.ValidatedChainstate()); |
| 2366 | const CChain& index_chain = chainstate.m_chain; |
| 2367 | const int current_height = WITH_LOCK(::cs_main, return index_chain.Height()); |
| 2368 | |
| 2369 | // Skip checking data availability if we have not synced any blocks yet |
| 2370 | if (current_height > 0) { |
| 2371 | // Before starting index sync, verify that all required block data is available |
| 2372 | // on disk from each index's current sync position up to the chain tip. |
| 2373 | // |
| 2374 | // This is done separately for undo and block data: First we verify block + undo |
| 2375 | // data existence from tip down to the lowest height required by any index that |
| 2376 | // needs undo data (e.g., coinstatsindex, blockfilterindex). Then, if any |
| 2377 | // block-only index needs to sync from a lower height than previously covered, |
| 2378 | // verify block data existence down to that lower height. |
| 2379 | // |
| 2380 | // This avoids checking undo data for blocks where no index requires it, |
| 2381 | // though currently block and undo data availability are synchronized on disk |
| 2382 | // under normal circumstances. |
| 2383 | std::optional<const CBlockIndex*> block_start; |
| 2384 | std::string block_start_name; |
| 2385 | std::optional<const CBlockIndex*> undo_start; |
| 2386 | std::string undo_start_name; |
| 2387 | |
| 2388 | for (const auto& index : node.indexes) { |
| 2389 | const IndexSummary& summary = index->GetSummary(); |
| 2390 | if (summary.synced) continue; |
| 2391 | |
| 2392 | // Get the last common block between the index best block and the active chain |
| 2393 | const CBlockIndex* pindex = nullptr; |
| 2394 | { |
| 2395 | LOCK(::cs_main); |
| 2396 | pindex = chainman.m_blockman.LookupBlockIndex(summary.best_block_hash); |
| 2397 | if (!pindex) { |
| 2398 | LogWarning("Failed to find block manager entry for best block %s from %s, falling back to genesis for index sync", |
| 2399 | summary.best_block_hash.ToString(), summary.name); |
| 2400 | } else if (!index_chain.Contains(*pindex)) { |
| 2401 | pindex = index_chain.FindFork(*pindex); |
| 2402 | } |
| 2403 | } |
| 2404 | if (!pindex) { |
| 2405 | pindex = index_chain.Genesis(); |
| 2406 | } |
| 2407 | |
| 2408 | bool need_undo = index->CustomOptions().connect_undo_data; |
| 2409 | auto& op_start_index = need_undo ? undo_start : block_start; |
| 2410 | auto& name_index = need_undo ? undo_start_name : block_start_name; |
| 2411 | |
| 2412 | if (op_start_index && pindex->nHeight >= op_start_index.value()->nHeight) continue; |
| 2413 | op_start_index = pindex; |
| 2414 | name_index = summary.name; |
| 2415 | } |
| 2416 | |
| 2417 | // Verify all blocks needed to sync to current tip are present including undo data. |
| 2418 | if (undo_start) { |
| 2419 | LOCK(::cs_main); |
no test coverage detected