Skip to content

Commit b51e60f

Browse files
author
MacroFake
committed
Merge bitcoin/bitcoin#22564: refactor: Move mutable globals cleared in ::UnloadBlockIndex to BlockManager
7ab07e0 validation: Prune UnloadBlockIndex and callees (Carl Dong) 7d99d72 validation: No mempool clearing in UnloadBlockIndex (Carl Dong) 572d831 Clear {versionbits,warning}cache in ~Chainstatemanager (Carl Dong) eca4ca4 style-only: Use std::clamp for check_ratio, rename (Carl Dong) fe96a2e style-only: Use for instead of when loading Chainstate (Carl Dong) 5921b86 init: Reset mempool and chainman via reconstruction (Carl Dong) 6e747e8 validation: default initialize and guard chainman members (Anthony Towns) 98f4bda 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 972c516: ``` 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. bitcoin/bitcoin@3585b52 The need to reason about when we need to manually call `::UnloadBlockIndex` (this decision can at times seem almost arbitrary) 2. bitcoin/bitcoin@f741623 The need to have an `::UnloadBlockIndex` or explicit `~ChainstateManager` at all ACKs for top commit: MarcoFalke: ACK 7ab07e0 👘 ajtowns: ACK 7ab07e0 ryanofsky: Code review ACK 7ab07e0. This all looks good and simplifies things nicely. I left some minor suggestions below but feel free to ignore. Tree-SHA512: a36ee3fc122ce0b4e8d1c432662d7009df06264b724b793252978a1e409dde7a7ef1f78b9ade3f8bfb5388213f10ae2d058d57a7a46ae563e9034d7d33a52b69
2 parents 9446de1 + 7ab07e0 commit b51e60f

10 files changed

+39
-87
lines changed

src/bitcoin-chainstate.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,5 @@ int main(int argc, char* argv[])
256256
}
257257
GetMainSignals().UnregisterBackgroundSignalScheduler();
258258

259-
WITH_LOCK(::cs_main, UnloadBlockIndex(nullptr, chainman));
260-
261259
init::UnsetGlobals();
262260
}

src/init.cpp

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
#include <validationinterface.h>
7474
#include <walletinitinterface.h>
7575

76+
#include <algorithm>
7677
#include <condition_variable>
7778
#include <cstdint>
7879
#include <cstdio>
@@ -1288,19 +1289,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
12881289
// as they would never get updated.
12891290
if (!ignores_incoming_txs) node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
12901291

1291-
assert(!node.mempool);
1292-
int check_ratio = std::min<int>(std::max<int>(args.GetIntArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
1293-
node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get(), check_ratio);
1294-
1295-
assert(!node.chainman);
1296-
node.chainman = std::make_unique<ChainstateManager>();
1297-
ChainstateManager& chainman = *node.chainman;
1298-
1299-
assert(!node.peerman);
1300-
node.peerman = PeerManager::make(chainparams, *node.connman, *node.addrman, node.banman.get(),
1301-
chainman, *node.mempool, ignores_incoming_txs);
1302-
RegisterValidationInterface(node.peerman.get());
1303-
13041292
// sanitize comments per BIP-0014, format user agent and check total size
13051293
std::vector<std::string> uacomments;
13061294
for (const std::string& cmt : args.GetArgs("-uacomment")) {
@@ -1429,8 +1417,16 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
14291417
LogPrintf("* Using %.1f MiB for chain state database\n", cache_sizes.coins_db * (1.0 / 1024 / 1024));
14301418
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));
14311419

1432-
bool fLoaded = false;
1433-
while (!fLoaded && !ShutdownRequested()) {
1420+
assert(!node.mempool);
1421+
assert(!node.chainman);
1422+
const int mempool_check_ratio = std::clamp<int>(args.GetIntArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0, 1000000);
1423+
1424+
for (bool fLoaded = false; !fLoaded && !ShutdownRequested();) {
1425+
node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get(), mempool_check_ratio);
1426+
1427+
node.chainman = std::make_unique<ChainstateManager>();
1428+
ChainstateManager& chainman = *node.chainman;
1429+
14341430
const bool fReset = fReindex;
14351431
bilingual_str strLoadError;
14361432

@@ -1562,6 +1558,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
15621558
return false;
15631559
}
15641560

1561+
ChainstateManager& chainman = *Assert(node.chainman);
1562+
1563+
assert(!node.peerman);
1564+
node.peerman = PeerManager::make(chainparams, *node.connman, *node.addrman, node.banman.get(),
1565+
chainman, *node.mempool, ignores_incoming_txs);
1566+
RegisterValidationInterface(node.peerman.get());
1567+
15651568
// ********************************************************* Step 8: start indexers
15661569
if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
15671570
if (const auto error{WITH_LOCK(cs_main, return CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db)))}) {

src/node/blockstorage.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -297,20 +297,6 @@ bool BlockManager::LoadBlockIndex(const Consensus::Params& consensus_params)
297297
return true;
298298
}
299299

300-
void BlockManager::Unload()
301-
{
302-
m_blocks_unlinked.clear();
303-
304-
m_block_index.clear();
305-
306-
m_blockfile_info.clear();
307-
m_last_blockfile = 0;
308-
m_dirty_blockindex.clear();
309-
m_dirty_fileinfo.clear();
310-
311-
m_have_pruned = false;
312-
}
313-
314300
bool BlockManager::WriteBlockIndexDB()
315301
{
316302
AssertLockHeld(::cs_main);

src/node/blockstorage.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,6 @@ class BlockManager
154154
bool WriteBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
155155
bool LoadBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
156156

157-
/** Clear all data members. */
158-
void Unload() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
159-
160157
CBlockIndex* AddToBlockIndex(const CBlockHeader& block, CBlockIndex*& best_header) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
161158
/** Create a new block index entry for a given block hash */
162159
CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -189,11 +186,6 @@ class BlockManager
189186

190187
//! Create or update a prune lock identified by its name
191188
void UpdatePruneLock(const std::string& name, const PruneLockInfo& lock_info) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
192-
193-
~BlockManager()
194-
{
195-
Unload();
196-
}
197189
};
198190

199191
//! Find the first block that is not pruned

src/node/chainstate.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
3232
chainman.m_total_coinstip_cache = nCoinCacheUsage;
3333
chainman.m_total_coinsdb_cache = nCoinDBCache;
3434

35-
UnloadBlockIndex(mempool, chainman);
36-
3735
auto& pblocktree{chainman.m_blockman.m_block_tree_db};
3836
// new CBlockTreeDB tries to delete the existing file, which
3937
// fails if it's still open from the previous loop. Close it first:

src/test/util/setup_common.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,6 @@ ChainTestingSetup::~ChainTestingSetup()
182182
m_node.addrman.reset();
183183
m_node.netgroupman.reset();
184184
m_node.args = nullptr;
185-
WITH_LOCK(::cs_main, UnloadBlockIndex(m_node.mempool.get(), *m_node.chainman));
186185
m_node.mempool.reset();
187186
m_node.scheduler.reset();
188187
m_node.chainman.reset();

src/test/validation_chainstate_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup)
9393
BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(m_node, m_path_root));
9494

9595
// Ensure our active chain is the snapshot chainstate.
96-
BOOST_CHECK(chainman.IsSnapshotActive());
96+
BOOST_CHECK(WITH_LOCK(::cs_main, return chainman.IsSnapshotActive()));
9797

9898
curr_tip = ::g_best_block;
9999

src/test/validation_chainstatemanager_tests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
4545
WITH_LOCK(::cs_main, c1.InitCoinsCache(1 << 23));
4646

4747
BOOST_CHECK(!manager.IsSnapshotActive());
48-
BOOST_CHECK(!manager.IsSnapshotValidated());
48+
BOOST_CHECK(WITH_LOCK(::cs_main, return !manager.IsSnapshotValidated()));
4949
auto all = manager.GetAll();
5050
BOOST_CHECK_EQUAL_COLLECTIONS(all.begin(), all.end(), chainstates.begin(), chainstates.end());
5151

@@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
7878
BOOST_CHECK(c2.ActivateBestChain(_, nullptr));
7979

8080
BOOST_CHECK(manager.IsSnapshotActive());
81-
BOOST_CHECK(!manager.IsSnapshotValidated());
81+
BOOST_CHECK(WITH_LOCK(::cs_main, return !manager.IsSnapshotValidated()));
8282
BOOST_CHECK_EQUAL(&c2, &manager.ActiveChainstate());
8383
BOOST_CHECK(&c1 != &manager.ActiveChainstate());
8484
auto all2 = manager.GetAll();

src/validation.cpp

Lines changed: 14 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,7 +1921,7 @@ class WarningBitsConditionChecker : public AbstractThresholdConditionChecker
19211921
}
19221922
};
19231923

1924-
static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS] GUARDED_BY(cs_main);
1924+
static std::array<ThresholdConditionCache, VERSIONBITS_NUM_BITS> warningcache GUARDED_BY(cs_main);
19251925

19261926
static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const Consensus::Params& consensusparams)
19271927
{
@@ -2550,7 +2550,7 @@ void CChainState::UpdateTip(const CBlockIndex* pindexNew)
25502550
const CBlockIndex* pindex = pindexNew;
25512551
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
25522552
WarningBitsConditionChecker checker(bit);
2553-
ThresholdState state = checker.GetStateFor(pindex, m_params.GetConsensus(), warningcache[bit]);
2553+
ThresholdState state = checker.GetStateFor(pindex, m_params.GetConsensus(), warningcache.at(bit));
25542554
if (state == ThresholdState::ACTIVE || state == ThresholdState::LOCKED_IN) {
25552555
const bilingual_str warning = strprintf(_("Unknown new rules activated (versionbit %i)"), bit);
25562556
if (state == ThresholdState::ACTIVE) {
@@ -4143,20 +4143,6 @@ void CChainState::UnloadBlockIndex()
41434143
setBlockIndexCandidates.clear();
41444144
}
41454145

4146-
// May NOT be used after any connections are up as much
4147-
// of the peer-processing logic assumes a consistent
4148-
// block index state
4149-
void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman)
4150-
{
4151-
AssertLockHeld(::cs_main);
4152-
chainman.Unload();
4153-
if (mempool) mempool->clear();
4154-
g_versionbitscache.Clear();
4155-
for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
4156-
warningcache[b].clear();
4157-
}
4158-
}
4159-
41604146
bool ChainstateManager::LoadBlockIndex()
41614147
{
41624148
AssertLockHeld(cs_main);
@@ -5187,20 +5173,6 @@ bool ChainstateManager::IsSnapshotActive() const
51875173
return m_snapshot_chainstate && m_active_chainstate == m_snapshot_chainstate.get();
51885174
}
51895175

5190-
void ChainstateManager::Unload()
5191-
{
5192-
AssertLockHeld(::cs_main);
5193-
for (CChainState* chainstate : this->GetAll()) {
5194-
chainstate->m_chain.SetTip(nullptr);
5195-
chainstate->UnloadBlockIndex();
5196-
}
5197-
5198-
m_failed_blocks.clear();
5199-
m_blockman.Unload();
5200-
m_best_header = nullptr;
5201-
m_best_invalid = nullptr;
5202-
}
5203-
52045176
void ChainstateManager::MaybeRebalanceCaches()
52055177
{
52065178
AssertLockHeld(::cs_main);
@@ -5231,3 +5203,15 @@ void ChainstateManager::MaybeRebalanceCaches()
52315203
}
52325204
}
52335205
}
5206+
5207+
ChainstateManager::~ChainstateManager()
5208+
{
5209+
LOCK(::cs_main);
5210+
5211+
// TODO: The version bits cache and warning cache should probably become
5212+
// non-globals
5213+
g_versionbitscache.Clear();
5214+
for (auto& i : warningcache) {
5215+
i.clear();
5216+
}
5217+
}

src/validation.h

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,6 @@ extern arith_uint256 nMinimumChainWork;
134134
/** Documentation for argument 'checklevel'. */
135135
extern const std::vector<std::string> CHECKLEVEL_DOC;
136136

137-
/** Unload database information */
138-
void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
139137
/** Run instances of script checking worker threads */
140138
void StartScriptCheckWorkerThreads(int threads_num);
141139
/** Stop all of the script checking worker threads */
@@ -831,9 +829,9 @@ class ChainstateManager
831829

832830
//! If true, the assumed-valid chainstate has been fully validated
833831
//! by the background validation chainstate.
834-
bool m_snapshot_validated{false};
832+
bool m_snapshot_validated GUARDED_BY(::cs_main){false};
835833

836-
CBlockIndex* m_best_invalid;
834+
CBlockIndex* m_best_invalid GUARDED_BY(::cs_main){nullptr};
837835

838836
//! Internal helper for ActivateSnapshot().
839837
[[nodiscard]] bool PopulateAndValidateSnapshot(
@@ -940,7 +938,7 @@ class ChainstateManager
940938
std::optional<uint256> SnapshotBlockhash() const;
941939

942940
//! Is there a snapshot in use and has it been fully validated?
943-
bool IsSnapshotValidated() const { return m_snapshot_validated; }
941+
bool IsSnapshotValidated() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { return m_snapshot_validated; }
944942

945943
/**
946944
* Process an incoming block. This only returns after the best known valid
@@ -988,17 +986,11 @@ class ChainstateManager
988986
//! Load the block tree and coins database from disk, initializing state if we're running with -reindex
989987
bool LoadBlockIndex() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
990988

991-
//! Unload block index and chain data before shutdown.
992-
void Unload() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
993-
994989
//! Check to see if caches are out of balance and if so, call
995990
//! ResizeCoinsCaches() as needed.
996991
void MaybeRebalanceCaches() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
997992

998-
~ChainstateManager() {
999-
LOCK(::cs_main);
1000-
UnloadBlockIndex(/*mempool=*/nullptr, *this);
1001-
}
993+
~ChainstateManager();
1002994
};
1003995

1004996
using FopenFn = std::function<FILE*(const fs::path&, const char*)>;

0 commit comments

Comments
 (0)