aboutsummaryrefslogtreecommitdiff
path: root/src/init.cpp
diff options
context:
space:
mode:
authorJames O'Beirne <james.obeirne@gmail.com>2019-07-24 13:23:48 -0400
committerJames O'Beirne <james.obeirne@gmail.com>2019-08-15 11:04:10 -0400
commit569353068568444a25b301bbd6513bb510157dc9 (patch)
tree72a8ffd5e3cbdbc71f5f4957dbb2feab55f6b2c2 /src/init.cpp
parentfae6ab6aed3b9fdc9201bb19a307dfc3d9b89891 (diff)
refactor: have CCoins* data managed under CChainState
This change encapsulates UTXO set data within CChainState instances, removing global data `pcoinsTip` and `pcoinsviewdb`. This is necessary if we want to maintain multiple chainstates with their own rendering of the UTXO set. We introduce a class CoinsViews which consolidates the construction of a CCoins* hierarchy. Construction of its various pieces (db, coinscatcher, in-memory cache) is split up so that we avoid flushing bad state to disk if startup is interrupted. We also introduce `CChainState::CanFlushToDisk()` which tells us when it is safe to flush the chainstate based on this partial construction. This commit could be broken into smaller pieces, but it would require more ephemeral diffs to, e.g., temporarily change CCoinsViewDB's constructor invocations. Other changes: - A parameter has been added to the CCoinsViewDB constructor that allows the name of the corresponding leveldb directory to be specified. Thanks to Russell Yanofsky and Marco Falke for helpful feedback.
Diffstat (limited to 'src/init.cpp')
-rw-r--r--src/init.cpp46
1 files changed, 25 insertions, 21 deletions
diff --git a/src/init.cpp b/src/init.cpp
index bb3ff8d88f..50ae0c6252 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -15,7 +15,6 @@
#include <blockfilter.h>
#include <chain.h>
#include <chainparams.h>
-#include <coins.h>
#include <compat/sanity.h>
#include <consensus/validation.h>
#include <fs.h>
@@ -149,7 +148,6 @@ NODISCARD static bool CreatePidFile()
// shutdown thing.
//
-static std::unique_ptr<CCoinsViewErrorCatcher> pcoinscatcher;
static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle;
static boost::thread_group threadGroup;
@@ -234,8 +232,11 @@ void Shutdown(InitInterfaces& interfaces)
}
// FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing
- if (pcoinsTip != nullptr) {
- ::ChainstateActive().ForceFlushStateToDisk();
+ //
+ // g_chainstate is referenced here directly (instead of ::ChainstateActive()) because it
+ // may not have been initialized yet.
+ if (g_chainstate && g_chainstate->CanFlushToDisk()) {
+ g_chainstate->ForceFlushStateToDisk();
}
// After there are no more peers/RPC left to give us new data which may generate
@@ -250,12 +251,10 @@ void Shutdown(InitInterfaces& interfaces)
{
LOCK(cs_main);
- if (pcoinsTip != nullptr) {
- ::ChainstateActive().ForceFlushStateToDisk();
+ if (g_chainstate && g_chainstate->CanFlushToDisk()) {
+ g_chainstate->ForceFlushStateToDisk();
+ g_chainstate->ResetCoinsViews();
}
- pcoinsTip.reset();
- pcoinscatcher.reset();
- pcoinsdbview.reset();
pblocktree.reset();
}
for (const auto& client : interfaces.chain_clients) {
@@ -1466,10 +1465,10 @@ bool AppInitMain(InitInterfaces& interfaces)
bool is_coinsview_empty;
try {
LOCK(cs_main);
+ // This statement makes ::ChainstateActive() usable.
+ g_chainstate = MakeUnique<CChainState>();
UnloadBlockIndex();
- pcoinsTip.reset();
- pcoinsdbview.reset();
- pcoinscatcher.reset();
+
// new CBlockTreeDB tries to delete the existing file, which
// fails if it's still open from the previous loop. Close it first:
pblocktree.reset();
@@ -1520,9 +1519,12 @@ bool AppInitMain(InitInterfaces& interfaces)
// At this point we're either in reindex or we've loaded a useful
// block tree into BlockIndex()!
- pcoinsdbview.reset(new CCoinsViewDB(nCoinDBCache, false, fReset || fReindexChainState));
- pcoinscatcher.reset(new CCoinsViewErrorCatcher(pcoinsdbview.get()));
- pcoinscatcher->AddReadErrCallback([]() {
+ ::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);
@@ -1530,23 +1532,25 @@ bool AppInitMain(InitInterfaces& interfaces)
// If necessary, upgrade from older database format.
// This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
- if (!pcoinsdbview->Upgrade()) {
+ 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 (!ReplayBlocks(chainparams, pcoinsdbview.get())) {
+ if (!ReplayBlocks(chainparams, &::ChainstateActive().CoinsDB())) {
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
- pcoinsTip.reset(new CCoinsViewCache(pcoinscatcher.get()));
+ ::ChainstateActive().InitCoinsCache();
+ assert(::ChainstateActive().CanFlushToDisk());
- is_coinsview_empty = fReset || fReindexChainState || pcoinsTip->GetBestBlock().IsNull();
+ is_coinsview_empty = fReset || fReindexChainState ||
+ ::ChainstateActive().CoinsTip().GetBestBlock().IsNull();
if (!is_coinsview_empty) {
- // LoadChainTip sets ::ChainActive() based on pcoinsTip's best block
+ // LoadChainTip sets ::ChainActive() based on CoinsTip()'s best block
if (!LoadChainTip(chainparams)) {
strLoadError = _("Error initializing block database").translated;
break;
@@ -1588,7 +1592,7 @@ bool AppInitMain(InitInterfaces& interfaces)
break;
}
- if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview.get(), gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
+ if (!CVerifyDB().VerifyDB(chainparams, &::ChainstateActive().CoinsDB(), gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
strLoadError = _("Corrupted block database detected").translated;
break;