aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMacroFake <falke.marco@gmail.com>2022-04-28 12:13:59 +0200
committerMacroFake <falke.marco@gmail.com>2022-04-28 12:14:06 +0200
commitb51e60f91472da5216116626afc032acd5616e85 (patch)
tree9fcf4b4b6781d7c6fb3d332e289a217725ec6e75
parent9446de160f37ccf9d639960f38bc1e4337b0c5f7 (diff)
parent7ab07e033237d6ea179a6a2c76575ed6bd01a670 (diff)
Merge bitcoin/bitcoin#22564: refactor: Move mutable globals cleared in `::UnloadBlockIndex` to `BlockManager`
7ab07e033237d6ea179a6a2c76575ed6bd01a670 validation: Prune UnloadBlockIndex and callees (Carl Dong) 7d99d725cdb5428ed25dc07c2d7fddf420da7786 validation: No mempool clearing in UnloadBlockIndex (Carl Dong) 572d8319272ae84a81d6bfd53dd9685585697f65 Clear {versionbits,warning}cache in ~Chainstatemanager (Carl Dong) eca4ca4d60599c9dbdd4e03a73beb33e9b44655a style-only: Use std::clamp for check_ratio, rename (Carl Dong) fe96a2e4bd87768df8001eb4117926a0977d876e style-only: Use for instead of when loading Chainstate (Carl Dong) 5921b863e39e5c3997895ffee1c87159e37a5d6f init: Reset mempool and chainman via reconstruction (Carl Dong) 6e747e80e7094df0b5bee1eed57e57e82015d0ee validation: default initialize and guard chainman members (Anthony Towns) 98f4bdae81804de17f125bd7c2cd8a48e850a6d2 refactor: Convert warningcache to std::array (Carl Dong) Pull request description: Fixes #22964 ----- This is a small part of the work to accomplish what I described in 972c5166ee685447a6d4bf5e501b07a0871fba85: ``` Over time, we should probably move these mutable global state variables into ChainstateManager or CChainState so it's easier to reason about their lifecycles. ``` `::UnloadBlockIndex` manually resets a subset of our mutable globals in addition to unloading the `ChainstateManager` and clearing the mempool. The need for this manual reset (AFAICT) arises out of the fact that many of these globals are closely related to the block index (hence `::UnloadBlockIndex`), and need to be reset with it. I've shot this "manual reset" gun at my foot several times while doing the de-globalize chainman work. Thankfully, now that we have a `BlockManager` class that owns the block index, these globals should be moved under that class so that they can live and die with the block index. These moves, along with making the block index non-heap-based, eliminates: 1. https://github.com/bitcoin/bitcoin/commit/3585b521392c5b2c855c3ba6dc9b7d2a171b3710 The need to reason about when we need to manually call `::UnloadBlockIndex` (this decision can at times seem almost arbitrary) 2. https://github.com/bitcoin/bitcoin/commit/f741623c25455c20bff9eb1ddd10a4ac84dc5655 The need to have an `::UnloadBlockIndex` or explicit `~ChainstateManager` at all ACKs for top commit: MarcoFalke: ACK 7ab07e033237d6ea179a6a2c76575ed6bd01a670 👘 ajtowns: ACK 7ab07e033237d6ea179a6a2c76575ed6bd01a670 ryanofsky: Code review ACK 7ab07e033237d6ea179a6a2c76575ed6bd01a670. This all looks good and simplifies things nicely. I left some minor suggestions below but feel free to ignore. Tree-SHA512: a36ee3fc122ce0b4e8d1c432662d7009df06264b724b793252978a1e409dde7a7ef1f78b9ade3f8bfb5388213f10ae2d058d57a7a46ae563e9034d7d33a52b69
-rw-r--r--src/bitcoin-chainstate.cpp2
-rw-r--r--src/init.cpp33
-rw-r--r--src/node/blockstorage.cpp14
-rw-r--r--src/node/blockstorage.h8
-rw-r--r--src/node/chainstate.cpp2
-rw-r--r--src/test/util/setup_common.cpp1
-rw-r--r--src/test/validation_chainstate_tests.cpp2
-rw-r--r--src/test/validation_chainstatemanager_tests.cpp4
-rw-r--r--src/validation.cpp44
-rw-r--r--src/validation.h16
10 files changed, 39 insertions, 87 deletions
diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp
index fcbb6aacce..1e4200db02 100644
--- a/src/bitcoin-chainstate.cpp
+++ b/src/bitcoin-chainstate.cpp
@@ -256,7 +256,5 @@ epilogue:
}
GetMainSignals().UnregisterBackgroundSignalScheduler();
- WITH_LOCK(::cs_main, UnloadBlockIndex(nullptr, chainman));
-
init::UnsetGlobals();
}
diff --git a/src/init.cpp b/src/init.cpp
index cccb088eec..fdcb2b8ac7 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -73,6 +73,7 @@
#include <validationinterface.h>
#include <walletinitinterface.h>
+#include <algorithm>
#include <condition_variable>
#include <cstdint>
#include <cstdio>
@@ -1288,19 +1289,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// as they would never get updated.
if (!ignores_incoming_txs) node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
- assert(!node.mempool);
- int check_ratio = std::min<int>(std::max<int>(args.GetIntArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
- node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get(), check_ratio);
-
- assert(!node.chainman);
- node.chainman = std::make_unique<ChainstateManager>();
- ChainstateManager& chainman = *node.chainman;
-
- assert(!node.peerman);
- node.peerman = PeerManager::make(chainparams, *node.connman, *node.addrman, node.banman.get(),
- chainman, *node.mempool, ignores_incoming_txs);
- RegisterValidationInterface(node.peerman.get());
-
// sanitize comments per BIP-0014, format user agent and check total size
std::vector<std::string> uacomments;
for (const std::string& cmt : args.GetArgs("-uacomment")) {
@@ -1429,8 +1417,16 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
LogPrintf("* Using %.1f MiB for chain state database\n", cache_sizes.coins_db * (1.0 / 1024 / 1024));
LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", cache_sizes.coins * (1.0 / 1024 / 1024), nMempoolSizeMax * (1.0 / 1024 / 1024));
- bool fLoaded = false;
- while (!fLoaded && !ShutdownRequested()) {
+ assert(!node.mempool);
+ assert(!node.chainman);
+ const int mempool_check_ratio = std::clamp<int>(args.GetIntArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0, 1000000);
+
+ for (bool fLoaded = false; !fLoaded && !ShutdownRequested();) {
+ node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get(), mempool_check_ratio);
+
+ node.chainman = std::make_unique<ChainstateManager>();
+ ChainstateManager& chainman = *node.chainman;
+
const bool fReset = fReindex;
bilingual_str strLoadError;
@@ -1562,6 +1558,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
return false;
}
+ ChainstateManager& chainman = *Assert(node.chainman);
+
+ assert(!node.peerman);
+ node.peerman = PeerManager::make(chainparams, *node.connman, *node.addrman, node.banman.get(),
+ chainman, *node.mempool, ignores_incoming_txs);
+ RegisterValidationInterface(node.peerman.get());
+
// ********************************************************* Step 8: start indexers
if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
if (const auto error{WITH_LOCK(cs_main, return CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db)))}) {
diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp
index 8ed22bbbce..25771aacee 100644
--- a/src/node/blockstorage.cpp
+++ b/src/node/blockstorage.cpp
@@ -297,20 +297,6 @@ bool BlockManager::LoadBlockIndex(const Consensus::Params& consensus_params)
return true;
}
-void BlockManager::Unload()
-{
- m_blocks_unlinked.clear();
-
- m_block_index.clear();
-
- m_blockfile_info.clear();
- m_last_blockfile = 0;
- m_dirty_blockindex.clear();
- m_dirty_fileinfo.clear();
-
- m_have_pruned = false;
-}
-
bool BlockManager::WriteBlockIndexDB()
{
AssertLockHeld(::cs_main);
diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h
index e4b9657372..622eac7fef 100644
--- a/src/node/blockstorage.h
+++ b/src/node/blockstorage.h
@@ -154,9 +154,6 @@ public:
bool WriteBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
bool LoadBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
- /** Clear all data members. */
- void Unload() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-
CBlockIndex* AddToBlockIndex(const CBlockHeader& block, CBlockIndex*& best_header) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Create a new block index entry for a given block hash */
CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -189,11 +186,6 @@ public:
//! Create or update a prune lock identified by its name
void UpdatePruneLock(const std::string& name, const PruneLockInfo& lock_info) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
-
- ~BlockManager()
- {
- Unload();
- }
};
//! Find the first block that is not pruned
diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp
index e43211402c..99615dea69 100644
--- a/src/node/chainstate.cpp
+++ b/src/node/chainstate.cpp
@@ -32,8 +32,6 @@ std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
chainman.m_total_coinstip_cache = nCoinCacheUsage;
chainman.m_total_coinsdb_cache = nCoinDBCache;
- UnloadBlockIndex(mempool, chainman);
-
auto& pblocktree{chainman.m_blockman.m_block_tree_db};
// new CBlockTreeDB tries to delete the existing file, which
// fails if it's still open from the previous loop. Close it first:
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 1830ec05af..2fc71c2a6e 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -182,7 +182,6 @@ ChainTestingSetup::~ChainTestingSetup()
m_node.addrman.reset();
m_node.netgroupman.reset();
m_node.args = nullptr;
- WITH_LOCK(::cs_main, UnloadBlockIndex(m_node.mempool.get(), *m_node.chainman));
m_node.mempool.reset();
m_node.scheduler.reset();
m_node.chainman.reset();
diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp
index b0d7389d39..2a3990bb7c 100644
--- a/src/test/validation_chainstate_tests.cpp
+++ b/src/test/validation_chainstate_tests.cpp
@@ -93,7 +93,7 @@ BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup)
BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(m_node, m_path_root));
// Ensure our active chain is the snapshot chainstate.
- BOOST_CHECK(chainman.IsSnapshotActive());
+ BOOST_CHECK(WITH_LOCK(::cs_main, return chainman.IsSnapshotActive()));
curr_tip = ::g_best_block;
diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp
index 5d0ec593e3..6dc522b421 100644
--- a/src/test/validation_chainstatemanager_tests.cpp
+++ b/src/test/validation_chainstatemanager_tests.cpp
@@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
WITH_LOCK(::cs_main, c1.InitCoinsCache(1 << 23));
BOOST_CHECK(!manager.IsSnapshotActive());
- BOOST_CHECK(!manager.IsSnapshotValidated());
+ BOOST_CHECK(WITH_LOCK(::cs_main, return !manager.IsSnapshotValidated()));
auto all = manager.GetAll();
BOOST_CHECK_EQUAL_COLLECTIONS(all.begin(), all.end(), chainstates.begin(), chainstates.end());
@@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
BOOST_CHECK(c2.ActivateBestChain(_, nullptr));
BOOST_CHECK(manager.IsSnapshotActive());
- BOOST_CHECK(!manager.IsSnapshotValidated());
+ BOOST_CHECK(WITH_LOCK(::cs_main, return !manager.IsSnapshotValidated()));
BOOST_CHECK_EQUAL(&c2, &manager.ActiveChainstate());
BOOST_CHECK(&c1 != &manager.ActiveChainstate());
auto all2 = manager.GetAll();
diff --git a/src/validation.cpp b/src/validation.cpp
index 3676316f76..208bcee008 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1921,7 +1921,7 @@ public:
}
};
-static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS] GUARDED_BY(cs_main);
+static std::array<ThresholdConditionCache, VERSIONBITS_NUM_BITS> warningcache GUARDED_BY(cs_main);
static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const Consensus::Params& consensusparams)
{
@@ -2550,7 +2550,7 @@ void CChainState::UpdateTip(const CBlockIndex* pindexNew)
const CBlockIndex* pindex = pindexNew;
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
WarningBitsConditionChecker checker(bit);
- ThresholdState state = checker.GetStateFor(pindex, m_params.GetConsensus(), warningcache[bit]);
+ ThresholdState state = checker.GetStateFor(pindex, m_params.GetConsensus(), warningcache.at(bit));
if (state == ThresholdState::ACTIVE || state == ThresholdState::LOCKED_IN) {
const bilingual_str warning = strprintf(_("Unknown new rules activated (versionbit %i)"), bit);
if (state == ThresholdState::ACTIVE) {
@@ -4143,20 +4143,6 @@ void CChainState::UnloadBlockIndex()
setBlockIndexCandidates.clear();
}
-// May NOT be used after any connections are up as much
-// of the peer-processing logic assumes a consistent
-// block index state
-void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman)
-{
- AssertLockHeld(::cs_main);
- chainman.Unload();
- if (mempool) mempool->clear();
- g_versionbitscache.Clear();
- for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
- warningcache[b].clear();
- }
-}
-
bool ChainstateManager::LoadBlockIndex()
{
AssertLockHeld(cs_main);
@@ -5187,20 +5173,6 @@ bool ChainstateManager::IsSnapshotActive() const
return m_snapshot_chainstate && m_active_chainstate == m_snapshot_chainstate.get();
}
-void ChainstateManager::Unload()
-{
- AssertLockHeld(::cs_main);
- for (CChainState* chainstate : this->GetAll()) {
- chainstate->m_chain.SetTip(nullptr);
- chainstate->UnloadBlockIndex();
- }
-
- m_failed_blocks.clear();
- m_blockman.Unload();
- m_best_header = nullptr;
- m_best_invalid = nullptr;
-}
-
void ChainstateManager::MaybeRebalanceCaches()
{
AssertLockHeld(::cs_main);
@@ -5231,3 +5203,15 @@ void ChainstateManager::MaybeRebalanceCaches()
}
}
}
+
+ChainstateManager::~ChainstateManager()
+{
+ LOCK(::cs_main);
+
+ // TODO: The version bits cache and warning cache should probably become
+ // non-globals
+ g_versionbitscache.Clear();
+ for (auto& i : warningcache) {
+ i.clear();
+ }
+}
diff --git a/src/validation.h b/src/validation.h
index 38d3d98465..e3ea8617e7 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -134,8 +134,6 @@ extern arith_uint256 nMinimumChainWork;
/** Documentation for argument 'checklevel'. */
extern const std::vector<std::string> CHECKLEVEL_DOC;
-/** Unload database information */
-void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
/** Run instances of script checking worker threads */
void StartScriptCheckWorkerThreads(int threads_num);
/** Stop all of the script checking worker threads */
@@ -831,9 +829,9 @@ private:
//! If true, the assumed-valid chainstate has been fully validated
//! by the background validation chainstate.
- bool m_snapshot_validated{false};
+ bool m_snapshot_validated GUARDED_BY(::cs_main){false};
- CBlockIndex* m_best_invalid;
+ CBlockIndex* m_best_invalid GUARDED_BY(::cs_main){nullptr};
//! Internal helper for ActivateSnapshot().
[[nodiscard]] bool PopulateAndValidateSnapshot(
@@ -940,7 +938,7 @@ public:
std::optional<uint256> SnapshotBlockhash() const;
//! Is there a snapshot in use and has it been fully validated?
- bool IsSnapshotValidated() const { return m_snapshot_validated; }
+ bool IsSnapshotValidated() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { return m_snapshot_validated; }
/**
* Process an incoming block. This only returns after the best known valid
@@ -988,17 +986,11 @@ public:
//! Load the block tree and coins database from disk, initializing state if we're running with -reindex
bool LoadBlockIndex() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- //! Unload block index and chain data before shutdown.
- void Unload() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
-
//! Check to see if caches are out of balance and if so, call
//! ResizeCoinsCaches() as needed.
void MaybeRebalanceCaches() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
- ~ChainstateManager() {
- LOCK(::cs_main);
- UnloadBlockIndex(/*mempool=*/nullptr, *this);
- }
+ ~ChainstateManager();
};
using FopenFn = std::function<FILE*(const fs::path&, const char*)>;