mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-12 12:52:35 -03:00
Merge bitcoin/bitcoin#21523: validation: run VerifyDB on all chainstates
844ad0ecca
doc: IsSnapshotActive (James O'Beirne)9b604c0207
validation: prepare VerifyDB for assumeutxo (James O'Beirne)7901647d72
refactor: rename active_chainstate in VerifyDB (James O'Beirne) Pull request description: This is part of the [assumeutxo project](https://github.com/bitcoin/bitcoin/projects/11) (parent PR: #15606) --- ~~Pretty cut and dry; parameterizes `CVerifyDB` methods so that we can run the verify procedure on multiple chainstates.~~ Two minor tweaks to ensure that `VerifyDB` can be run on multiple chainstates and a corresponding rename. ACKs for top commit: fjahr: Code review re-ACK844ad0ecca
MarcoFalke: review ACK844ad0ecca
🐥 Tree-SHA512: 26a398cf4dabc1aa0850743921dba0452b4813848a3c777586dc981716737e98e17b8110254a5c41af95dd236e0c00dc8b4eee891d69bef825a5e1911fc499d0
This commit is contained in:
commit
c6d6bc8abb
4 changed files with 41 additions and 26 deletions
|
@ -1525,11 +1525,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only verify the DB of the active chainstate. This is fixed in later
|
if (!CVerifyDB().VerifyDB(
|
||||||
// work when we allow VerifyDB to be parameterized by chainstate.
|
*chainstate, chainparams, chainstate->CoinsDB(),
|
||||||
if (&::ChainstateActive() == chainstate &&
|
|
||||||
!CVerifyDB().VerifyDB(
|
|
||||||
chainparams, *chainstate, &chainstate->CoinsDB(),
|
|
||||||
args.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
|
args.GetArg("-checklevel", DEFAULT_CHECKLEVEL),
|
||||||
args.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
|
args.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) {
|
||||||
strLoadError = _("Corrupted block database detected");
|
strLoadError = _("Corrupted block database detected");
|
||||||
|
|
|
@ -1239,7 +1239,8 @@ static RPCHelpMan verifychain()
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
CChainState& active_chainstate = chainman.ActiveChainstate();
|
CChainState& active_chainstate = chainman.ActiveChainstate();
|
||||||
return CVerifyDB().VerifyDB(Params(), active_chainstate, &active_chainstate.CoinsTip(), check_level, check_depth);
|
return CVerifyDB().VerifyDB(
|
||||||
|
active_chainstate, Params(), active_chainstate.CoinsTip(), check_level, check_depth);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -4101,38 +4101,46 @@ CVerifyDB::~CVerifyDB()
|
||||||
uiInterface.ShowProgress("", 100, false);
|
uiInterface.ShowProgress("", 100, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CChainState& active_chainstate, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth)
|
bool CVerifyDB::VerifyDB(
|
||||||
|
CChainState& chainstate,
|
||||||
|
const CChainParams& chainparams,
|
||||||
|
CCoinsView& coinsview,
|
||||||
|
int nCheckLevel, int nCheckDepth)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
assert(std::addressof(::ChainstateActive()) == std::addressof(active_chainstate));
|
assert(std::addressof(::ChainstateActive()) == std::addressof(chainstate));
|
||||||
if (active_chainstate.m_chain.Tip() == nullptr || active_chainstate.m_chain.Tip()->pprev == nullptr)
|
if (chainstate.m_chain.Tip() == nullptr || chainstate.m_chain.Tip()->pprev == nullptr)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Verify blocks in the best chain
|
// Verify blocks in the best chain
|
||||||
if (nCheckDepth <= 0 || nCheckDepth > active_chainstate.m_chain.Height())
|
if (nCheckDepth <= 0 || nCheckDepth > chainstate.m_chain.Height())
|
||||||
nCheckDepth = active_chainstate.m_chain.Height();
|
nCheckDepth = chainstate.m_chain.Height();
|
||||||
nCheckLevel = std::max(0, std::min(4, nCheckLevel));
|
nCheckLevel = std::max(0, std::min(4, nCheckLevel));
|
||||||
LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
|
LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
|
||||||
CCoinsViewCache coins(coinsview);
|
CCoinsViewCache coins(&coinsview);
|
||||||
CBlockIndex* pindex;
|
CBlockIndex* pindex;
|
||||||
CBlockIndex* pindexFailure = nullptr;
|
CBlockIndex* pindexFailure = nullptr;
|
||||||
int nGoodTransactions = 0;
|
int nGoodTransactions = 0;
|
||||||
BlockValidationState state;
|
BlockValidationState state;
|
||||||
int reportDone = 0;
|
int reportDone = 0;
|
||||||
LogPrintf("[0%%]..."); /* Continued */
|
LogPrintf("[0%%]..."); /* Continued */
|
||||||
for (pindex = active_chainstate.m_chain.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) {
|
|
||||||
const int percentageDone = std::max(1, std::min(99, (int)(((double)(active_chainstate.m_chain.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))));
|
bool is_snapshot_cs = !chainstate.m_from_snapshot_blockhash.IsNull();
|
||||||
|
|
||||||
|
for (pindex = chainstate.m_chain.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) {
|
||||||
|
const int percentageDone = std::max(1, std::min(99, (int)(((double)(chainstate.m_chain.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))));
|
||||||
if (reportDone < percentageDone/10) {
|
if (reportDone < percentageDone/10) {
|
||||||
// report every 10% step
|
// report every 10% step
|
||||||
LogPrintf("[%d%%]...", percentageDone); /* Continued */
|
LogPrintf("[%d%%]...", percentageDone); /* Continued */
|
||||||
reportDone = percentageDone/10;
|
reportDone = percentageDone/10;
|
||||||
}
|
}
|
||||||
uiInterface.ShowProgress(_("Verifying blocks...").translated, percentageDone, false);
|
uiInterface.ShowProgress(_("Verifying blocks...").translated, percentageDone, false);
|
||||||
if (pindex->nHeight <= active_chainstate.m_chain.Height()-nCheckDepth)
|
if (pindex->nHeight <= chainstate.m_chain.Height()-nCheckDepth)
|
||||||
break;
|
break;
|
||||||
if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
|
if ((fPruneMode || is_snapshot_cs) && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
|
||||||
// If pruning, only go back as far as we have data.
|
// If pruning or running under an assumeutxo snapshot, only go
|
||||||
|
// back as far as we have data.
|
||||||
LogPrintf("VerifyDB(): block verification stopping at height %d (pruning, no data)\n", pindex->nHeight);
|
LogPrintf("VerifyDB(): block verification stopping at height %d (pruning, no data)\n", pindex->nHeight);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4154,9 +4162,11 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CChainState& active_ch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
|
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
|
||||||
if (nCheckLevel >= 3 && (coins.DynamicMemoryUsage() + active_chainstate.CoinsTip().DynamicMemoryUsage()) <= active_chainstate.m_coinstip_cache_size_bytes) {
|
size_t curr_coins_usage = coins.DynamicMemoryUsage() + chainstate.CoinsTip().DynamicMemoryUsage();
|
||||||
|
|
||||||
|
if (nCheckLevel >= 3 && curr_coins_usage <= chainstate.m_coinstip_cache_size_bytes) {
|
||||||
assert(coins.GetBestBlock() == pindex->GetBlockHash());
|
assert(coins.GetBestBlock() == pindex->GetBlockHash());
|
||||||
DisconnectResult res = active_chainstate.DisconnectBlock(block, pindex, coins);
|
DisconnectResult res = chainstate.DisconnectBlock(block, pindex, coins);
|
||||||
if (res == DISCONNECT_FAILED) {
|
if (res == DISCONNECT_FAILED) {
|
||||||
return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
|
return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
|
||||||
}
|
}
|
||||||
|
@ -4170,26 +4180,26 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CChainState& active_ch
|
||||||
if (ShutdownRequested()) return true;
|
if (ShutdownRequested()) return true;
|
||||||
}
|
}
|
||||||
if (pindexFailure)
|
if (pindexFailure)
|
||||||
return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", active_chainstate.m_chain.Height() - pindexFailure->nHeight + 1, nGoodTransactions);
|
return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainstate.m_chain.Height() - pindexFailure->nHeight + 1, nGoodTransactions);
|
||||||
|
|
||||||
// store block count as we move pindex at check level >= 4
|
// store block count as we move pindex at check level >= 4
|
||||||
int block_count = active_chainstate.m_chain.Height() - pindex->nHeight;
|
int block_count = chainstate.m_chain.Height() - pindex->nHeight;
|
||||||
|
|
||||||
// check level 4: try reconnecting blocks
|
// check level 4: try reconnecting blocks
|
||||||
if (nCheckLevel >= 4) {
|
if (nCheckLevel >= 4) {
|
||||||
while (pindex != active_chainstate.m_chain.Tip()) {
|
while (pindex != chainstate.m_chain.Tip()) {
|
||||||
const int percentageDone = std::max(1, std::min(99, 100 - (int)(((double)(active_chainstate.m_chain.Height() - pindex->nHeight)) / (double)nCheckDepth * 50)));
|
const int percentageDone = std::max(1, std::min(99, 100 - (int)(((double)(chainstate.m_chain.Height() - pindex->nHeight)) / (double)nCheckDepth * 50)));
|
||||||
if (reportDone < percentageDone/10) {
|
if (reportDone < percentageDone/10) {
|
||||||
// report every 10% step
|
// report every 10% step
|
||||||
LogPrintf("[%d%%]...", percentageDone); /* Continued */
|
LogPrintf("[%d%%]...", percentageDone); /* Continued */
|
||||||
reportDone = percentageDone/10;
|
reportDone = percentageDone/10;
|
||||||
}
|
}
|
||||||
uiInterface.ShowProgress(_("Verifying blocks...").translated, percentageDone, false);
|
uiInterface.ShowProgress(_("Verifying blocks...").translated, percentageDone, false);
|
||||||
pindex = active_chainstate.m_chain.Next(pindex);
|
pindex = chainstate.m_chain.Next(pindex);
|
||||||
CBlock block;
|
CBlock block;
|
||||||
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus()))
|
if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus()))
|
||||||
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
|
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
|
||||||
if (!active_chainstate.ConnectBlock(block, state, pindex, coins, chainparams))
|
if (!chainstate.ConnectBlock(block, state, pindex, coins, chainparams))
|
||||||
return error("VerifyDB(): *** found unconnectable block at %d, hash=%s (%s)", pindex->nHeight, pindex->GetBlockHash().ToString(), state.ToString());
|
return error("VerifyDB(): *** found unconnectable block at %d, hash=%s (%s)", pindex->nHeight, pindex->GetBlockHash().ToString(), state.ToString());
|
||||||
if (ShutdownRequested()) return true;
|
if (ShutdownRequested()) return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -329,7 +329,12 @@ class CVerifyDB {
|
||||||
public:
|
public:
|
||||||
CVerifyDB();
|
CVerifyDB();
|
||||||
~CVerifyDB();
|
~CVerifyDB();
|
||||||
bool VerifyDB(const CChainParams& chainparams, CChainState& active_chainstate, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool VerifyDB(
|
||||||
|
CChainState& chainstate,
|
||||||
|
const CChainParams& chainparams,
|
||||||
|
CCoinsView& coinsview,
|
||||||
|
int nCheckLevel,
|
||||||
|
int nCheckDepth) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DisconnectResult
|
enum DisconnectResult
|
||||||
|
@ -913,6 +918,8 @@ public:
|
||||||
return m_blockman.m_block_index;
|
return m_blockman.m_block_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! @returns true if a snapshot-based chainstate is in use. Also implies
|
||||||
|
//! that a background validation chainstate is also in use.
|
||||||
bool IsSnapshotActive() const;
|
bool IsSnapshotActive() const;
|
||||||
|
|
||||||
std::optional<uint256> SnapshotBlockhash() const;
|
std::optional<uint256> SnapshotBlockhash() const;
|
||||||
|
|
Loading…
Reference in a new issue