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.
This commit is contained in:
James O'Beirne
2019-07-24 13:23:48 -04:00
parent fae6ab6aed
commit 5693530685
7 changed files with 170 additions and 43 deletions

View File

@@ -82,11 +82,17 @@ namespace {
BlockManager g_blockman;
} // anon namespace
static CChainState g_chainstate(g_blockman);
std::unique_ptr<CChainState> g_chainstate;
CChainState& ChainstateActive() { return g_chainstate; }
CChainState& ChainstateActive() {
assert(g_chainstate);
return *g_chainstate;
}
CChain& ChainActive() { return g_chainstate.m_chain; }
CChain& ChainActive() {
assert(g_chainstate);
return g_chainstate->m_chain;
}
/**
* Mutex to guard access to validation specific variables, such as reading
@@ -173,8 +179,6 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
return chain.Genesis();
}
std::unique_ptr<CCoinsViewDB> pcoinsdbview;
std::unique_ptr<CCoinsViewCache> pcoinsTip;
std::unique_ptr<CBlockTreeDB> pblocktree;
// See definition for documentation
@@ -525,7 +529,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
}
// Note: this call may add txin.prevout to the coins cache
// (pcoinsTip.cacheCoins) by way of FetchCoin(). It should be removed
// (CoinsTip().cacheCoins) by way of FetchCoin(). It should be removed
// later (via coins_to_uncache) if this tx turns out to be invalid.
if (!view.HaveCoin(txin.prevout)) {
// Are inputs missing because we already have the tx?
@@ -1041,6 +1045,40 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
return nSubsidy;
}
CoinsViews::CoinsViews(
std::string ldb_name,
size_t cache_size_bytes,
bool in_memory,
bool should_wipe) : m_dbview(
GetDataDir() / ldb_name, cache_size_bytes, in_memory, should_wipe),
m_catcherview(&m_dbview) {}
void CoinsViews::InitCache()
{
m_cacheview = MakeUnique<CCoinsViewCache>(&m_catcherview);
}
// NOTE: for now m_blockman is set to a global, but this will be changed
// in a future commit.
CChainState::CChainState() : m_blockman(g_blockman) {}
void CChainState::InitCoinsDB(
size_t cache_size_bytes,
bool in_memory,
bool should_wipe,
std::string leveldb_name)
{
m_coins_views = MakeUnique<CoinsViews>(
leveldb_name, cache_size_bytes, in_memory, should_wipe);
}
void CChainState::InitCoinsCache()
{
assert(m_coins_views != nullptr);
m_coins_views->InitCache();
}
// Note that though this is marked const, we may end up modifying `m_cached_finished_ibd`, which
// is a performance-related implementation detail. This function must be marked
// `const` so that `CValidationInterface` clients (which are given a `const CChainState*`)
@@ -1982,6 +2020,7 @@ bool CChainState::FlushStateToDisk(
{
int64_t nMempoolUsage = mempool.DynamicMemoryUsage();
LOCK(cs_main);
assert(this->CanFlushToDisk());
static int64_t nLastWrite = 0;
static int64_t nLastFlush = 0;
std::set<int> setFilesToPrune;