init, validation: Improve handling if VerifyDB() fails due to insufficient dbcache

The rpc command verifychain now fails if the dbcache was not sufficient
to complete the verification at the specified level and depth.

In the same situation, the VerifyDB check during Init will now fail (and lead to
an early shutdown) if the user has explicitly specified -checkblocks or
-checklevel but the check couldn't be executed because of the limited
cache. If the user didn't change any of the two and is using the defaults, log a warning
but don't prevent the node from starting up.
This commit is contained in:
Martin Zumsande 2022-10-06 17:11:02 -04:00
parent d6f781f1cf
commit 0c7785bb25
7 changed files with 21 additions and 3 deletions

View file

@ -1502,6 +1502,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
options.prune = chainman.m_blockman.IsPruneMode();
options.check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
options.check_level = args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL);
options.require_full_verification = args.IsArgSet("-checkblocks") || args.IsArgSet("-checklevel");
options.check_interrupt = ShutdownRequested;
options.coins_error_cb = [] {
uiInterface.ThreadSafeMessageBox(
@ -1533,7 +1534,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
}
}
if (status == node::ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB) {
if (status == node::ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB || status == node::ChainstateLoadStatus::FAILURE_INSUFFICIENT_DBCACHE) {
return InitError(error);
}

View file

@ -197,6 +197,11 @@ ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const C
break;
case VerifyDBResult::CORRUPTED_BLOCK_DB:
return {ChainstateLoadStatus::FAILURE, _("Corrupted block database detected")};
case VerifyDBResult::SKIPPED_L3_CHECKS:
if (options.require_full_verification) {
return {ChainstateLoadStatus::FAILURE_INSUFFICIENT_DBCACHE, _("Insufficient dbcache for block verification")};
}
break;
} // no default case, so the compiler can warn about missing cases
}
}

View file

@ -25,6 +25,7 @@ struct ChainstateLoadOptions {
bool reindex{false};
bool reindex_chainstate{false};
bool prune{false};
bool require_full_verification{true};
int64_t check_blocks{DEFAULT_CHECKBLOCKS};
int64_t check_level{DEFAULT_CHECKLEVEL};
std::function<bool()> check_interrupt;
@ -35,7 +36,13 @@ struct ChainstateLoadOptions {
//! case, and treat other cases as errors. More complex applications may want to
//! try reindexing in the generic failure case, and pass an interrupt callback
//! and exit cleanly in the interrupted case.
enum class ChainstateLoadStatus { SUCCESS, FAILURE, FAILURE_INCOMPATIBLE_DB, INTERRUPTED };
enum class ChainstateLoadStatus {
SUCCESS,
FAILURE,
FAILURE_INCOMPATIBLE_DB,
FAILURE_INSUFFICIENT_DBCACHE,
INTERRUPTED,
};
//! Chainstate load status code and optional error string.
using ChainstateLoadResult = std::tuple<ChainstateLoadStatus, bilingual_str>;

View file

@ -1110,7 +1110,7 @@ static RPCHelpMan verifychain()
{"nblocks", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%d, 0=all", DEFAULT_CHECKBLOCKS)}, "The number of blocks to check."},
},
RPCResult{
RPCResult::Type::BOOL, "", "Verified or not"},
RPCResult::Type::BOOL, "", "Verification finished successfully. If false, check debug.log for reason."},
RPCExamples{
HelpExampleCli("verifychain", "")
+ HelpExampleRpc("verifychain", "")

View file

@ -218,6 +218,7 @@ void TestingSetup::LoadVerifyActivateChainstate()
options.prune = chainman.m_blockman.IsPruneMode();
options.check_blocks = m_args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
options.check_level = m_args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL);
options.require_full_verification = m_args.IsArgSet("-checkblocks") || m_args.IsArgSet("-checklevel");
auto [status, error] = LoadChainstate(chainman, m_cache_sizes, options);
assert(status == node::ChainstateLoadStatus::SUCCESS);

View file

@ -4185,6 +4185,9 @@ VerifyDBResult CVerifyDB::VerifyDB(
LogPrintf("Verification: No coin database inconsistencies in last %i blocks (%i transactions)\n", block_count, nGoodTransactions);
if (skipped_l3_checks) {
return VerifyDBResult::SKIPPED_L3_CHECKS;
}
return VerifyDBResult::SUCCESS;
}

View file

@ -353,6 +353,7 @@ enum class VerifyDBResult {
SUCCESS,
CORRUPTED_BLOCK_DB,
INTERRUPTED,
SKIPPED_L3_CHECKS,
};
/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */