chain: add CChain::IsTipRecent helper

Factor the chain tip work/recency check out of `ChainstateManager::IsInitialBlockDownload()` into a reusable `CChain::IsTipRecent()` helper, and annotate it as requiring `cs_main` since it's reading mutable state.

Also introduce a local `chainman_ref` in the kernel import-blocks wrapper to reduce repetition and keep follow-up diffs small.

`IsInitialBlockDownload` returns were also unified to make the followup move clean.

Co-authored-by: Patrick Strateman <patrick.strateman@gmail.com>
Co-authored-by: Martin Zumsande <mzumsande@gmail.com>
This commit is contained in:
Lőrinc 2026-01-11 23:56:21 +01:00
parent 8d531c6210
commit b9c0ab3b75
No known key found for this signature in database
GPG Key ID: 669FFF0FFA477A76
3 changed files with 15 additions and 18 deletions

View File

@ -420,6 +420,15 @@ public:
return int(vChain.size()) - 1;
}
/** Check whether this chain's tip exists, has enough work, and is recent. */
bool IsTipRecent(const arith_uint256& min_chain_work, std::chrono::seconds max_tip_age) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
const auto tip{Tip()};
return tip &&
tip->nChainWork >= min_chain_work &&
tip->Time() >= Now<NodeSeconds>() - max_tip_age;
}
/** Set/initialize a chain with a given tip. */
void SetTip(CBlockIndex& block);

View File

@ -1054,7 +1054,8 @@ int btck_chainstate_manager_import_blocks(btck_ChainstateManager* chainman, cons
import_files.emplace_back(std::string{block_file_paths_data[i], block_file_paths_lens[i]}.c_str());
}
}
node::ImportBlocks(*btck_ChainstateManager::get(chainman).m_chainman, import_files);
auto& chainman_ref{*btck_ChainstateManager::get(chainman).m_chainman};
node::ImportBlocks(chainman_ref, import_files);
} catch (const std::exception& e) {
LogError("Failed to import blocks: %s", e.what());
return -1;

View File

@ -1947,25 +1947,12 @@ void Chainstate::InitCoinsCache(size_t cache_size_bytes)
bool ChainstateManager::IsInitialBlockDownload() const
{
// Optimization: pre-test latch before taking the lock.
if (!m_cached_is_ibd.load(std::memory_order_relaxed))
return false;
if (!m_cached_is_ibd.load(std::memory_order_relaxed)) return false;
LOCK(cs_main);
if (!m_cached_is_ibd.load(std::memory_order_relaxed))
return false;
if (m_blockman.LoadingBlocks()) {
return true;
}
CChain& chain{ActiveChain()};
if (chain.Tip() == nullptr) {
return true;
}
if (chain.Tip()->nChainWork < MinimumChainWork()) {
return true;
}
if (chain.Tip()->Time() < Now<NodeSeconds>() - m_options.max_tip_age) {
return true;
}
if (!m_cached_is_ibd.load(std::memory_order_relaxed)) return false;
if (m_blockman.LoadingBlocks()) return true;
if (!ActiveChain().IsTipRecent(MinimumChainWork(), m_options.max_tip_age)) return true;
LogInfo("Leaving InitialBlockDownload (latching to false)");
m_cached_is_ibd.store(false, std::memory_order_relaxed);
return false;