aboutsummaryrefslogtreecommitdiff
path: root/src/init.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/init.cpp')
-rw-r--r--src/init.cpp193
1 files changed, 117 insertions, 76 deletions
diff --git a/src/init.cpp b/src/init.cpp
index 765c61b3db..56b63c8101 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -233,13 +233,12 @@ void Shutdown(NodeContext& node)
}
// FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing
- //
- // g_chainstate is referenced here directly (instead of ::ChainstateActive()) because it
- // may not have been initialized yet.
{
LOCK(cs_main);
- if (g_chainstate && g_chainstate->CanFlushToDisk()) {
- g_chainstate->ForceFlushStateToDisk();
+ for (CChainState* chainstate : g_chainman.GetAll()) {
+ if (chainstate->CanFlushToDisk()) {
+ chainstate->ForceFlushStateToDisk();
+ }
}
}
@@ -263,9 +262,11 @@ void Shutdown(NodeContext& node)
{
LOCK(cs_main);
- if (g_chainstate && g_chainstate->CanFlushToDisk()) {
- g_chainstate->ForceFlushStateToDisk();
- g_chainstate->ResetCoinsViews();
+ for (CChainState* chainstate : g_chainman.GetAll()) {
+ if (chainstate->CanFlushToDisk()) {
+ chainstate->ForceFlushStateToDisk();
+ chainstate->ResetCoinsViews();
+ }
}
pblocktree.reset();
}
@@ -1502,17 +1503,18 @@ bool AppInitMain(NodeContext& node)
bool fLoaded = false;
while (!fLoaded && !ShutdownRequested()) {
bool fReset = fReindex;
+ auto is_coinsview_empty = [&](CChainState* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
+ return fReset || fReindexChainState || chainstate->CoinsTip().GetBestBlock().IsNull();
+ };
std::string strLoadError;
uiInterface.InitMessage(_("Loading block index...").translated);
do {
const int64_t load_block_index_start_time = GetTimeMillis();
- bool is_coinsview_empty;
try {
LOCK(cs_main);
- // This statement makes ::ChainstateActive() usable.
- g_chainstate = MakeUnique<CChainState>();
+ g_chainman.InitializeChainstate();
UnloadBlockIndex();
// new CBlockTreeDB tries to delete the existing file, which
@@ -1565,43 +1567,53 @@ bool AppInitMain(NodeContext& node)
// At this point we're either in reindex or we've loaded a useful
// block tree into BlockIndex()!
- ::ChainstateActive().InitCoinsDB(
- /* cache_size_bytes */ nCoinDBCache,
- /* in_memory */ false,
- /* should_wipe */ fReset || fReindexChainState);
-
- ::ChainstateActive().CoinsErrorCatcher().AddReadErrCallback([]() {
- uiInterface.ThreadSafeMessageBox(
- _("Error reading from database, shutting down.").translated,
- "", CClientUIInterface::MSG_ERROR);
- });
-
- // If necessary, upgrade from older database format.
- // This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
- if (!::ChainstateActive().CoinsDB().Upgrade()) {
- strLoadError = _("Error upgrading chainstate database").translated;
- break;
- }
-
- // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
- if (!::ChainstateActive().ReplayBlocks(chainparams)) {
- strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.").translated;
- break;
- }
-
- // The on-disk coinsdb is now in a good state, create the cache
- ::ChainstateActive().InitCoinsCache();
- assert(::ChainstateActive().CanFlushToDisk());
+ bool failed_chainstate_init = false;
+
+ for (CChainState* chainstate : g_chainman.GetAll()) {
+ LogPrintf("Initializing chainstate %s\n", chainstate->ToString());
+ chainstate->InitCoinsDB(
+ /* cache_size_bytes */ nCoinDBCache,
+ /* in_memory */ false,
+ /* should_wipe */ fReset || fReindexChainState);
+
+ chainstate->CoinsErrorCatcher().AddReadErrCallback([]() {
+ uiInterface.ThreadSafeMessageBox(
+ _("Error reading from database, shutting down.").translated,
+ "", CClientUIInterface::MSG_ERROR);
+ });
+
+ // If necessary, upgrade from older database format.
+ // This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
+ if (!chainstate->CoinsDB().Upgrade()) {
+ strLoadError = _("Error upgrading chainstate database").translated;
+ failed_chainstate_init = true;
+ break;
+ }
- is_coinsview_empty = fReset || fReindexChainState ||
- ::ChainstateActive().CoinsTip().GetBestBlock().IsNull();
- if (!is_coinsview_empty) {
- // LoadChainTip initializes the chain based on CoinsTip()'s best block
- if (!::ChainstateActive().LoadChainTip(chainparams)) {
- strLoadError = _("Error initializing block database").translated;
+ // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
+ if (!chainstate->ReplayBlocks(chainparams)) {
+ strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.").translated;
+ failed_chainstate_init = true;
break;
}
- assert(::ChainActive().Tip() != nullptr);
+
+ // The on-disk coinsdb is now in a good state, create the cache
+ chainstate->InitCoinsCache();
+ assert(chainstate->CanFlushToDisk());
+
+ if (!is_coinsview_empty(chainstate)) {
+ // LoadChainTip initializes the chain based on CoinsTip()'s best block
+ if (!chainstate->LoadChainTip(chainparams)) {
+ strLoadError = _("Error initializing block database").translated;
+ failed_chainstate_init = true;
+ break; // out of the per-chainstate loop
+ }
+ assert(chainstate->m_chain.Tip() != nullptr);
+ }
+ }
+
+ if (failed_chainstate_init) {
+ break; // out of the chainstate activation do-while
}
} catch (const std::exception& e) {
LogPrintf("%s\n", e.what());
@@ -1609,49 +1621,75 @@ bool AppInitMain(NodeContext& node)
break;
}
- if (!fReset) {
- // Note that RewindBlockIndex MUST run even if we're about to -reindex-chainstate.
- // It both disconnects blocks based on ::ChainActive(), and drops block data in
- // BlockIndex() based on lack of available witness data.
- uiInterface.InitMessage(_("Rewinding blocks...").translated);
- if (!::ChainstateActive().RewindBlockIndex(chainparams)) {
- strLoadError = _("Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain").translated;
- break;
+ bool failed_rewind{false};
+
+ for (CChainState* chainstate : g_chainman.GetAll()) {
+ if (!fReset) {
+ // Note that RewindBlockIndex MUST run even if we're about to -reindex-chainstate.
+ // It both disconnects blocks based on the chainstate, and drops block data in
+ // BlockIndex() based on lack of available witness data.
+ uiInterface.InitMessage(_("Rewinding blocks...").translated);
+ if (!chainstate->RewindBlockIndex(chainparams)) {
+ strLoadError = _(
+ "Unable to rewind the database to a pre-fork state. "
+ "You will need to redownload the blockchain").translated;
+ failed_rewind = true;
+ break; // out of the per-chainstate loop
+ }
}
}
+ if (failed_rewind) {
+ break; // out of the chainstate activation do-while
+ }
+
+ bool failed_verification = false;
+
try {
LOCK(cs_main);
- if (!is_coinsview_empty) {
- uiInterface.InitMessage(_("Verifying blocks...").translated);
- if (fHavePruned && gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
- LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks\n",
- MIN_BLOCKS_TO_KEEP);
- }
- CBlockIndex* tip = ::ChainActive().Tip();
- RPCNotifyBlockChange(true, tip);
- if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) {
- strLoadError = _("The block database contains a block which appears to be from the future. "
- "This may be due to your computer's date and time being set incorrectly. "
- "Only rebuild the block database if you are sure that your computer's date and time are correct").translated;
- break;
- }
-
- if (!CVerifyDB().VerifyDB(chainparams, &::ChainstateActive().CoinsDB(), gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
- gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
- strLoadError = _("Corrupted block database detected").translated;
- break;
+ for (CChainState* chainstate : g_chainman.GetAll()) {
+ if (!is_coinsview_empty(chainstate)) {
+ uiInterface.InitMessage(_("Verifying blocks...").translated);
+ if (fHavePruned && gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) {
+ LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks\n",
+ MIN_BLOCKS_TO_KEEP);
+ }
+
+ const CBlockIndex* tip = chainstate->m_chain.Tip();
+ RPCNotifyBlockChange(true, tip);
+ if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) {
+ strLoadError = _("The block database contains a block which appears to be from the future. "
+ "This may be due to your computer's date and time being set incorrectly. "
+ "Only rebuild the block database if you are sure that your computer's date and time are correct").translated;
+ failed_verification = true;
+ break;
+ }
+
+ // Only verify the DB of the active chainstate. This is fixed in later
+ // work when we allow VerifyDB to be parameterized by chainstate.
+ if (&::ChainstateActive() == chainstate &&
+ !CVerifyDB().VerifyDB(
+ chainparams, &chainstate->CoinsDB(),
+ gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
+ gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
+ strLoadError = _("Corrupted block database detected").translated;
+ failed_verification = true;
+ break;
+ }
}
}
} catch (const std::exception& e) {
LogPrintf("%s\n", e.what());
strLoadError = _("Error opening block database").translated;
+ failed_verification = true;
break;
}
- fLoaded = true;
- LogPrintf(" block index %15dms\n", GetTimeMillis() - load_block_index_start_time);
+ if (!failed_verification) {
+ fLoaded = true;
+ LogPrintf(" block index %15dms\n", GetTimeMillis() - load_block_index_start_time);
+ }
} while(false);
if (!fLoaded && !ShutdownRequested()) {
@@ -1715,8 +1753,11 @@ bool AppInitMain(NodeContext& node)
LogPrintf("Unsetting NODE_NETWORK on prune mode\n");
nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK);
if (!fReindex) {
- uiInterface.InitMessage(_("Pruning blockstore...").translated);
- ::ChainstateActive().PruneAndFlush();
+ LOCK(cs_main);
+ for (CChainState* chainstate : g_chainman.GetAll()) {
+ uiInterface.InitMessage(_("Pruning blockstore...").translated);
+ chainstate->PruneAndFlush();
+ }
}
}