mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-18 13:17:55 +02:00
Merge 85883a9f8e into merged_master (Bitcoin PR #16443)
This commit is contained in:
commit
028f2d94d1
17 changed files with 247 additions and 100 deletions
|
|
@ -85,11 +85,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
|
||||
|
|
@ -176,8 +182,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
|
||||
|
|
@ -266,8 +270,8 @@ bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flag
|
|||
lockPair.second = lp->time;
|
||||
}
|
||||
else {
|
||||
// pcoinsTip contains the UTXO set for ::ChainActive().Tip()
|
||||
CCoinsViewMemPool viewMemPool(pcoinsTip.get(), pool);
|
||||
// CoinsTip() contains the UTXO set for ::ChainActive().Tip()
|
||||
CCoinsViewMemPool viewMemPool(&::ChainstateActive().CoinsTip(), pool);
|
||||
std::vector<int> prevheights;
|
||||
prevheights.resize(tx.vin.size());
|
||||
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
|
||||
|
|
@ -322,7 +326,8 @@ bool CheckSequenceLocks(const CTxMemPool& pool, const CTransaction& tx, int flag
|
|||
// Returns the script flags which should be checked for a given block
|
||||
static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& chainparams);
|
||||
|
||||
static void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
|
||||
static void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(pool.cs, ::cs_main)
|
||||
{
|
||||
int expired = pool.Expire(GetTime() - age);
|
||||
if (expired != 0) {
|
||||
|
|
@ -332,7 +337,7 @@ static void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age)
|
|||
std::vector<COutPoint> vNoSpendsRemaining;
|
||||
pool.TrimToSize(limit, &vNoSpendsRemaining);
|
||||
for (const COutPoint& removed : vNoSpendsRemaining)
|
||||
pcoinsTip->Uncache(removed);
|
||||
::ChainstateActive().CoinsTip().Uncache(removed);
|
||||
}
|
||||
|
||||
static bool IsCurrentForFeeEstimation() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||
|
|
@ -394,7 +399,7 @@ static void UpdateMempoolForReorg(DisconnectedBlockTransactions& disconnectpool,
|
|||
mempool.UpdateTransactionsFromBlock(vHashUpdate);
|
||||
|
||||
// We also need to remove any now-immature transactions
|
||||
mempool.removeForReorg(pcoinsTip.get(), ::ChainActive().Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
|
||||
mempool.removeForReorg(&::ChainstateActive().CoinsTip(), ::ChainActive().Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
|
||||
// Re-limit mempool size, in case we added any transactions
|
||||
LimitMempoolSize(mempool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60);
|
||||
}
|
||||
|
|
@ -430,7 +435,7 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationSt
|
|||
assert(txFrom->vout.size() > txin.prevout.n);
|
||||
assert(txFrom->vout[txin.prevout.n] == coin.out);
|
||||
} else {
|
||||
const Coin& coinFromDisk = pcoinsTip->AccessCoin(txin.prevout);
|
||||
const Coin& coinFromDisk = ::ChainstateActive().CoinsTip().AccessCoin(txin.prevout);
|
||||
assert(!coinFromDisk.IsSpent());
|
||||
assert(coinFromDisk.out == coin.out);
|
||||
}
|
||||
|
|
@ -531,7 +536,8 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
|
|||
std::set<std::pair<uint256, COutPoint> > setPeginsSpent;
|
||||
|
||||
LockPoints lp;
|
||||
CCoinsViewMemPool viewMemPool(pcoinsTip.get(), pool);
|
||||
CCoinsViewCache& coins_cache = ::ChainstateActive().CoinsTip();
|
||||
CCoinsViewMemPool viewMemPool(&coins_cache, pool);
|
||||
view.SetBackend(viewMemPool);
|
||||
|
||||
// Quickly check for peg-in witness data on non-peg-in inputs
|
||||
|
|
@ -570,18 +576,18 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!pcoinsTip->HaveCoinInCache(txin.prevout)) {
|
||||
if (!coins_cache.HaveCoinInCache(txin.prevout)) {
|
||||
coins_to_uncache.push_back(txin.prevout);
|
||||
}
|
||||
|
||||
// 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?
|
||||
for (size_t out = 0; out < tx.vout.size(); out++) {
|
||||
// Optimistically just do efficient check of cache for outputs
|
||||
if (pcoinsTip->HaveCoinInCache(COutPoint(hash, out))) {
|
||||
if (coins_cache.HaveCoinInCache(COutPoint(hash, out))) {
|
||||
return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, REJECT_DUPLICATE, "txn-already-known");
|
||||
}
|
||||
}
|
||||
|
|
@ -918,7 +924,7 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo
|
|||
// (`CCoinsViewCache::cacheCoins`).
|
||||
|
||||
for (const COutPoint& hashTx : coins_to_uncache)
|
||||
pcoinsTip->Uncache(hashTx);
|
||||
::ChainstateActive().CoinsTip().Uncache(hashTx);
|
||||
}
|
||||
// After we've (potentially) uncached entries, ensure our coins cache is still within its size limits
|
||||
CValidationState stateDummy;
|
||||
|
|
@ -1101,6 +1107,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*`)
|
||||
|
|
@ -2125,6 +2165,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;
|
||||
|
|
@ -2158,7 +2199,7 @@ bool CChainState::FlushStateToDisk(
|
|||
nLastFlush = nNow;
|
||||
}
|
||||
int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
|
||||
int64_t cacheSize = pcoinsTip->DynamicMemoryUsage();
|
||||
int64_t cacheSize = CoinsTip().DynamicMemoryUsage();
|
||||
int64_t nTotalSpace = nCoinCacheUsage + std::max<int64_t>(nMempoolSizeMax - nMempoolUsage, 0);
|
||||
// The cache is large and we're within 10% and 10 MiB of the limit, but we have time now (not in the middle of a block processing).
|
||||
bool fCacheLarge = mode == FlushStateMode::PERIODIC && cacheSize > std::max((9 * nTotalSpace) / 10, nTotalSpace - MAX_BLOCK_COINSDB_USAGE * 1024 * 1024);
|
||||
|
|
@ -2202,17 +2243,17 @@ bool CChainState::FlushStateToDisk(
|
|||
nLastWrite = nNow;
|
||||
}
|
||||
// Flush best chain related state. This can only be done if the blocks / block index write was also done.
|
||||
if (fDoFullFlush && !pcoinsTip->GetBestBlock().IsNull()) {
|
||||
if (fDoFullFlush && !CoinsTip().GetBestBlock().IsNull()) {
|
||||
// Typical Coin structures on disk are around 48 bytes in size.
|
||||
// Pushing a new one to the database can cause it to be written
|
||||
// twice (once in the log, and once in the tables). This is already
|
||||
// an overestimation, as most will delete an existing entry or
|
||||
// overwrite one. Still, use a conservative safety factor of 2.
|
||||
if (!CheckDiskSpace(GetDataDir(), 48 * 2 * 2 * pcoinsTip->GetCacheSize())) {
|
||||
if (!CheckDiskSpace(GetDataDir(), 48 * 2 * 2 * CoinsTip().GetCacheSize())) {
|
||||
return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!").translated, CClientUIInterface::MSG_NOPREFIX);
|
||||
}
|
||||
// Flush the chainstate (which may refer to block index entries).
|
||||
if (!pcoinsTip->Flush())
|
||||
if (!CoinsTip().Flush())
|
||||
return AbortNode(state, "Failed to write to coin database");
|
||||
nLastFlush = nNow;
|
||||
full_flush_completed = true;
|
||||
|
|
@ -2264,7 +2305,9 @@ static void AppendWarning(std::string& res, const std::string& warn)
|
|||
}
|
||||
|
||||
/** Check warning conditions and do some notifications on new chain tip set. */
|
||||
void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainParams) {
|
||||
void static UpdateTip(const CBlockIndex* pindexNew, const CChainParams& chainParams)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
|
||||
{
|
||||
// New best block
|
||||
mempool.AddTransactionsUpdated(1);
|
||||
|
||||
|
|
@ -2307,7 +2350,7 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar
|
|||
(unsigned long)pindexNew->nChainTx,
|
||||
FormatISO8601DateTime(pindexNew->GetBlockTime()),
|
||||
GuessVerificationProgress(pindexNew, chainParams.GetConsensus().nPowTargetSpacing),
|
||||
pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
|
||||
::ChainstateActive().CoinsTip().DynamicMemoryUsage() * (1.0 / (1<<20)), ::ChainstateActive().CoinsTip().GetCacheSize());
|
||||
if (!warningMessages.empty())
|
||||
LogPrintf(" warning='%s'", warningMessages); /* Continued */
|
||||
LogPrintf("\n");
|
||||
|
|
@ -2336,7 +2379,7 @@ bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& cha
|
|||
// Apply the block atomically to the chain state.
|
||||
int64_t nStart = GetTimeMicros();
|
||||
{
|
||||
CCoinsViewCache view(pcoinsTip.get());
|
||||
CCoinsViewCache view(&CoinsTip());
|
||||
assert(view.GetBestBlock() == pindexDelete->GetBlockHash());
|
||||
if (DisconnectBlock(block, pindexDelete, view) != DISCONNECT_OK)
|
||||
return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString());
|
||||
|
|
@ -2469,7 +2512,7 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp
|
|||
std::set<std::pair<uint256, COutPoint>> setPeginsSpent;
|
||||
|
||||
{
|
||||
CCoinsViewCache view(pcoinsTip.get());
|
||||
CCoinsViewCache view(&CoinsTip());
|
||||
bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, chainparams, &setPeginsSpent);
|
||||
GetMainSignals().BlockChecked(blockConnecting, state);
|
||||
if (!rv) {
|
||||
|
|
@ -2695,7 +2738,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar
|
|||
// any disconnected transactions back to the mempool.
|
||||
UpdateMempoolForReorg(disconnectpool, true);
|
||||
}
|
||||
mempool.check(pcoinsTip.get());
|
||||
mempool.check(&CoinsTip());
|
||||
|
||||
// Callbacks/notifications for a new best chain.
|
||||
if (fInvalidFound)
|
||||
|
|
@ -3797,7 +3840,7 @@ bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams,
|
|||
{
|
||||
AssertLockHeld(cs_main);
|
||||
assert(pindexPrev && pindexPrev == ::ChainActive().Tip());
|
||||
CCoinsViewCache viewNew(pcoinsTip.get());
|
||||
CCoinsViewCache viewNew(&::ChainstateActive().CoinsTip());
|
||||
uint256 block_hash(block.GetHash());
|
||||
CBlockIndex indexDummy(block);
|
||||
indexDummy.pprev = pindexPrev;
|
||||
|
|
@ -4150,12 +4193,14 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams) EXCLUSIVE_LOCKS_RE
|
|||
bool LoadChainTip(const CChainParams& chainparams)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
assert(!pcoinsTip->GetBestBlock().IsNull()); // Never called when the coins view is empty
|
||||
const CCoinsViewCache& coins_cache = ::ChainstateActive().CoinsTip();
|
||||
assert(!coins_cache.GetBestBlock().IsNull()); // Never called when the coins view is empty
|
||||
|
||||
if (::ChainActive().Tip() && ::ChainActive().Tip()->GetBlockHash() == pcoinsTip->GetBestBlock()) return true;
|
||||
if (::ChainActive().Tip() &&
|
||||
::ChainActive().Tip()->GetBlockHash() == coins_cache.GetBestBlock()) return true;
|
||||
|
||||
// Load pointer to end of best chain
|
||||
CBlockIndex* pindex = LookupBlockIndex(pcoinsTip->GetBestBlock());
|
||||
CBlockIndex* pindex = LookupBlockIndex(coins_cache.GetBestBlock());
|
||||
if (!pindex) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -4232,7 +4277,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
|
|||
}
|
||||
}
|
||||
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
|
||||
if (nCheckLevel >= 3 && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) {
|
||||
if (nCheckLevel >= 3 && (coins.DynamicMemoryUsage() + ::ChainstateActive().CoinsTip().DynamicMemoryUsage()) <= nCoinCacheUsage) {
|
||||
assert(coins.GetBestBlock() == pindex->GetBlockHash());
|
||||
DisconnectResult res = ::ChainstateActive().DisconnectBlock(block, pindex, coins);
|
||||
if (res == DISCONNECT_FAILED) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue