From 6a572dbda92ceb8c5af379f51cf6f9b93fb5e486 Mon Sep 17 00:00:00 2001 From: Ryan Ofsky Date: Thu, 30 May 2024 14:52:28 -0400 Subject: [PATCH] refactor: Add ChainstateManager::ActivateBestChains() method Deduplicate code looping over chainstate objects and calling ActivateBestChain() and avoid need for code outside ChainstateManager to use the GetAll() method. --- src/kernel/bitcoinkernel.cpp | 10 +++------- src/node/blockstorage.cpp | 12 ++---------- src/validation.cpp | 28 ++++++++++++++++++---------- src/validation.h | 3 +++ 4 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/kernel/bitcoinkernel.cpp b/src/kernel/bitcoinkernel.cpp index 3a36e2c8e76..5bb1a06b094 100644 --- a/src/kernel/bitcoinkernel.cpp +++ b/src/kernel/bitcoinkernel.cpp @@ -982,13 +982,9 @@ btck_ChainstateManager* btck_chainstate_manager_create( LogError("Failed to verify loaded chain state from your datadir: %s", chainstate_err.original); return nullptr; } - - for (Chainstate* chainstate : WITH_LOCK(chainman->GetMutex(), return chainman->GetAll())) { - BlockValidationState state; - if (!chainstate->ActivateBestChain(state, nullptr)) { - LogError("Failed to connect best block: %s", state.ToString()); - return nullptr; - } + if (auto result = chainman->ActivateBestChains(); !result) { + LogError("%s", util::ErrorString(result).original); + return nullptr; } } catch (const std::exception& e) { LogError("Failed to load chainstate: %s", e.what()); diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index c5d26e5cbb0..0bb22d901b7 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -1270,16 +1270,8 @@ void ImportBlocks(ChainstateManager& chainman, std::span import_ } // scan for better chains in the block chain database, that are not yet connected in the active best chain - - // We can't hold cs_main during ActivateBestChain even though we're accessing - // the chainman unique_ptrs since ABC requires us not to be holding cs_main, so retrieve - // the relevant pointers before the ABC call. - for (Chainstate* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) { - BlockValidationState state; - if (!chainstate->ActivateBestChain(state, nullptr)) { - chainman.GetNotifications().fatalError(strprintf(_("Failed to connect best block (%s)."), state.ToString())); - return; - } + if (auto result = chainman.ActivateBestChains(); !result) { + chainman.GetNotifications().fatalError(util::ErrorString(result)); } // End scope of ImportingNow } diff --git a/src/validation.cpp b/src/validation.cpp index 0d16dc209a6..cc080d017d7 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -5137,16 +5137,8 @@ void ChainstateManager::LoadExternalBlockFile( // until after all of the block files are loaded. ActivateBestChain can be // called by concurrent network message processing. but, that is not // reliable for the purpose of pruning while importing. - bool activation_failure = false; - for (auto c : GetAll()) { - BlockValidationState state; - if (!c->ActivateBestChain(state, pblock)) { - LogDebug(BCLog::REINDEX, "failed to activate chain (%s)\n", state.ToString()); - activation_failure = true; - break; - } - } - if (activation_failure) { + if (auto result{ActivateBestChains()}; !result) { + LogDebug(BCLog::REINDEX, "%s\n", util::ErrorString(result).original); break; } } @@ -6446,3 +6438,19 @@ std::optional> ChainstateManag if (!chainstate) return {}; return std::make_pair(chainstate->m_chain.Tip(), chainstate->TargetBlock()); } + +util::Result ChainstateManager::ActivateBestChains() +{ + // We can't hold cs_main during ActivateBestChain even though we're accessing + // the chainman unique_ptrs since ABC requires us not to be holding cs_main, so retrieve + // the relevant pointers before the ABC call. + AssertLockNotHeld(cs_main); + for (Chainstate* chainstate : GetAll()) { + BlockValidationState state; + if (!chainstate->ActivateBestChain(state, nullptr)) { + LOCK(GetMutex()); + return util::Error{Untranslated(strprintf("%s Failed to connect best block (%s)", chainstate->ToString(), state.ToString()))}; + } + } + return {}; +} diff --git a/src/validation.h b/src/validation.h index f330d90af4c..82fbf04d009 100644 --- a/src/validation.h +++ b/src/validation.h @@ -1337,6 +1337,9 @@ public: //! Get range of historical blocks to download. std::optional> GetHistoricalBlockRange() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + //! Call ActivateBestChain() on every chainstate. + util::Result ActivateBestChains() LOCKS_EXCLUDED(::cs_main); + //! If, due to invalidation / reconsideration of blocks, the previous //! best header is no longer valid / guaranteed to be the most-work //! header in our block-index not known to be invalid, recalculate it.