mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-13 19:37:04 +01:00
refactor: Use util::Result class in LoadChainstate and VerifyLoadedChainstate
This commit is contained in:
parent
6a18bcfcf8
commit
48949d1c60
5 changed files with 91 additions and 90 deletions
|
@ -129,13 +129,13 @@ int main(int argc, char* argv[])
|
|||
ChainstateManager chainman{interrupt, chainman_opts, blockman_opts};
|
||||
|
||||
node::ChainstateLoadOptions options;
|
||||
auto [status, error] = node::LoadChainstate(chainman, cache_sizes, options);
|
||||
if (status != node::ChainstateLoadStatus::SUCCESS) {
|
||||
auto load_result{node::LoadChainstate(chainman, cache_sizes, options)};
|
||||
if (!load_result) {
|
||||
std::cerr << "Failed to load Chain state from your datadir." << std::endl;
|
||||
goto epilogue;
|
||||
} else {
|
||||
std::tie(status, error) = node::VerifyLoadedChainstate(chainman, options);
|
||||
if (status != node::ChainstateLoadStatus::SUCCESS) {
|
||||
auto verify_result{node::VerifyLoadedChainstate(chainman, options)};
|
||||
if (!verify_result) {
|
||||
std::cerr << "Failed to verify loaded Chain state from your datadir." << std::endl;
|
||||
goto epilogue;
|
||||
}
|
||||
|
|
42
src/init.cpp
42
src/init.cpp
|
@ -120,12 +120,11 @@
|
|||
using common::AmountErrMsg;
|
||||
using common::InvalidPortErrMsg;
|
||||
using common::ResolveErrMsg;
|
||||
|
||||
using kernel::InterruptResult;
|
||||
using node::ApplyArgsManOptions;
|
||||
using node::BlockManager;
|
||||
using node::CalculateCacheSizes;
|
||||
using node::ChainstateLoadResult;
|
||||
using node::ChainstateLoadStatus;
|
||||
using node::ChainstateLoadError;
|
||||
using node::DEFAULT_PERSIST_MEMPOOL;
|
||||
using node::DEFAULT_PRINT_MODIFIED_FEE;
|
||||
using node::DEFAULT_STOPATHEIGHT;
|
||||
|
@ -1221,7 +1220,7 @@ bool CheckHostPortOptions(const ArgsManager& args) {
|
|||
|
||||
// A GUI user may opt to retry once with do_reindex set if there is a failure during chainstate initialization.
|
||||
// The function therefore has to support re-entry.
|
||||
static ChainstateLoadResult InitAndLoadChainstate(
|
||||
util::Result<kernel::InterruptResult, ChainstateLoadError> InitAndLoadChainstate(
|
||||
NodeContext& node,
|
||||
bool do_reindex,
|
||||
const bool do_reindex_chainstate,
|
||||
|
@ -1237,7 +1236,7 @@ static ChainstateLoadResult InitAndLoadChainstate(
|
|||
bilingual_str mempool_error;
|
||||
node.mempool = std::make_unique<CTxMemPool>(mempool_opts, mempool_error);
|
||||
if (!mempool_error.empty()) {
|
||||
return {ChainstateLoadStatus::FAILURE_FATAL, mempool_error};
|
||||
return {util::Error{mempool_error}, ChainstateLoadError::FAILURE_FATAL};
|
||||
}
|
||||
LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", cache_sizes.coins * (1.0 / 1024 / 1024), mempool_opts.max_size_bytes * (1.0 / 1024 / 1024));
|
||||
ChainstateManager::Options chainman_opts{
|
||||
|
@ -1267,12 +1266,12 @@ static ChainstateLoadResult InitAndLoadChainstate(
|
|||
node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown_signal), chainman_opts, blockman_opts);
|
||||
} catch (dbwrapper_error& e) {
|
||||
LogError("%s", e.what());
|
||||
return {ChainstateLoadStatus::FAILURE, _("Error opening block database")};
|
||||
return {util::Error{_("Error opening block database")}, ChainstateLoadError::FAILURE};
|
||||
} catch (std::exception& e) {
|
||||
return {ChainstateLoadStatus::FAILURE_FATAL, Untranslated(strprintf("Failed to initialize ChainstateManager: %s", e.what()))};
|
||||
return {util::Error{Untranslated(strprintf("Failed to initialize ChainstateManager: %s", e.what()))}, ChainstateLoadError::FAILURE_FATAL};
|
||||
}
|
||||
ChainstateManager& chainman = *node.chainman;
|
||||
if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};
|
||||
if (chainman.m_interrupt) return kernel::Interrupted{};
|
||||
|
||||
// This is defined and set here instead of inline in validation.h to avoid a hard
|
||||
// dependency between validation and index/base, since the latter is not in
|
||||
|
@ -1307,27 +1306,27 @@ static ChainstateLoadResult InitAndLoadChainstate(
|
|||
"", CClientUIInterface::MSG_ERROR);
|
||||
};
|
||||
uiInterface.InitMessage(_("Loading block index…"));
|
||||
auto catch_exceptions = [](auto&& f) -> ChainstateLoadResult {
|
||||
auto catch_exceptions = [](auto&& f) -> util::Result<InterruptResult, node::ChainstateLoadError> {
|
||||
try {
|
||||
return f();
|
||||
} catch (const std::exception& e) {
|
||||
LogError("%s\n", e.what());
|
||||
return std::make_tuple(node::ChainstateLoadStatus::FAILURE, _("Error loading databases"));
|
||||
return {util::Error{_("Error loading databases")}, node::ChainstateLoadError::FAILURE};
|
||||
}
|
||||
};
|
||||
auto [status, error] = catch_exceptions([&] { return LoadChainstate(chainman, cache_sizes, options); });
|
||||
if (status == node::ChainstateLoadStatus::SUCCESS) {
|
||||
auto result = catch_exceptions([&] { return LoadChainstate(chainman, cache_sizes, options); });
|
||||
if (result && !IsInterrupted(*result)) {
|
||||
uiInterface.InitMessage(_("Verifying blocks…"));
|
||||
if (chainman.m_blockman.m_have_pruned && options.check_blocks > MIN_BLOCKS_TO_KEEP) {
|
||||
LogWarning("pruned datadir may not have more than %d blocks; only checking available blocks\n",
|
||||
MIN_BLOCKS_TO_KEEP);
|
||||
}
|
||||
std::tie(status, error) = catch_exceptions([&] { return VerifyLoadedChainstate(chainman, options); });
|
||||
if (status == node::ChainstateLoadStatus::SUCCESS) {
|
||||
result.Update(catch_exceptions([&] { return VerifyLoadedChainstate(chainman, options); }));
|
||||
if (result && !IsInterrupted(*result)) {
|
||||
LogInfo("Block index and chainstate loaded");
|
||||
}
|
||||
}
|
||||
return {status, error};
|
||||
return result;
|
||||
};
|
||||
|
||||
bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
||||
|
@ -1685,14 +1684,15 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
|||
const bool do_reindex_chainstate{args.GetBoolArg("-reindex-chainstate", false)};
|
||||
|
||||
// Chainstate initialization and loading may be retried once with reindexing by GUI users
|
||||
auto [status, error] = InitAndLoadChainstate(
|
||||
auto result = InitAndLoadChainstate(
|
||||
node,
|
||||
do_reindex,
|
||||
do_reindex_chainstate,
|
||||
kernel_cache_sizes,
|
||||
args);
|
||||
if (status == ChainstateLoadStatus::FAILURE && !do_reindex && !ShutdownRequested(node)) {
|
||||
if (!result && result.GetFailure() == ChainstateLoadError::FAILURE && !do_reindex && !ShutdownRequested(node)) {
|
||||
// suggest a reindex
|
||||
const auto& error = util::ErrorString(result);
|
||||
bool do_retry = uiInterface.ThreadSafeQuestion(
|
||||
error + Untranslated(".\n\n") + _("Do you want to rebuild the databases now?"),
|
||||
error.original + ".\nPlease restart with -reindex or -reindex-chainstate to recover.",
|
||||
|
@ -1704,15 +1704,15 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
|||
if (!Assert(node.shutdown_signal)->reset()) {
|
||||
LogError("Internal error: failed to reset shutdown signal.\n");
|
||||
}
|
||||
std::tie(status, error) = InitAndLoadChainstate(
|
||||
result.Update(InitAndLoadChainstate(
|
||||
node,
|
||||
do_reindex,
|
||||
do_reindex_chainstate,
|
||||
kernel_cache_sizes,
|
||||
args);
|
||||
args));
|
||||
}
|
||||
if (status != ChainstateLoadStatus::SUCCESS && status != ChainstateLoadStatus::INTERRUPTED) {
|
||||
return InitError(error);
|
||||
if (!result) {
|
||||
return InitError(util::ErrorString(result));
|
||||
}
|
||||
|
||||
// As LoadBlockIndex can take several minutes, it's possible the user
|
||||
|
|
|
@ -27,35 +27,40 @@
|
|||
#include <vector>
|
||||
|
||||
using kernel::CacheSizes;
|
||||
using kernel::Interrupted;
|
||||
using kernel::InterruptResult;
|
||||
|
||||
namespace node {
|
||||
// Complete initialization of chainstates after the initial call has been made
|
||||
// to ChainstateManager::InitializeChainstate().
|
||||
static ChainstateLoadResult CompleteChainstateInitialization(
|
||||
static util::Result<InterruptResult, ChainstateLoadError> CompleteChainstateInitialization(
|
||||
ChainstateManager& chainman,
|
||||
const ChainstateLoadOptions& options) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
|
||||
{
|
||||
if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};
|
||||
if (chainman.m_interrupt) return Interrupted{};
|
||||
|
||||
// LoadBlockIndex will load m_have_pruned if we've ever removed a
|
||||
// block file from disk.
|
||||
// Note that it also sets m_blockfiles_indexed based on the disk flag!
|
||||
if (!chainman.LoadBlockIndex()) {
|
||||
if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};
|
||||
return {ChainstateLoadStatus::FAILURE, _("Error loading block database")};
|
||||
if (chainman.m_interrupt) {
|
||||
return Interrupted{};
|
||||
} else {
|
||||
return {util::Error{_("Error loading block database")}, ChainstateLoadError::FAILURE};
|
||||
}
|
||||
}
|
||||
|
||||
if (!chainman.BlockIndex().empty() &&
|
||||
!chainman.m_blockman.LookupBlockIndex(chainman.GetConsensus().hashGenesisBlock)) {
|
||||
// If the loaded chain has a wrong genesis, bail out immediately
|
||||
// (we're likely using a testnet datadir, or the other way around).
|
||||
return {ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB, _("Incorrect or no genesis block found. Wrong datadir for network?")};
|
||||
return {util::Error{_("Incorrect or no genesis block found. Wrong datadir for network?")}, ChainstateLoadError::FAILURE_INCOMPATIBLE_DB};
|
||||
}
|
||||
|
||||
// Check for changed -prune state. What we are concerned about is a user who has pruned blocks
|
||||
// in the past, but is now trying to run unpruned.
|
||||
if (chainman.m_blockman.m_have_pruned && !options.prune) {
|
||||
return {ChainstateLoadStatus::FAILURE, _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain")};
|
||||
return {util::Error{_("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain")}, ChainstateLoadError::FAILURE};
|
||||
}
|
||||
|
||||
// At this point blocktree args are consistent with what's on disk.
|
||||
|
@ -63,7 +68,7 @@ static ChainstateLoadResult CompleteChainstateInitialization(
|
|||
// (otherwise we use the one already on disk).
|
||||
// This is called again in ImportBlocks after the reindex completes.
|
||||
if (chainman.m_blockman.m_blockfiles_indexed && !chainman.ActiveChainstate().LoadGenesisBlock()) {
|
||||
return {ChainstateLoadStatus::FAILURE, _("Error initializing block database")};
|
||||
return {util::Error{_("Error initializing block database")}, ChainstateLoadError::FAILURE};
|
||||
}
|
||||
|
||||
auto is_coinsview_empty = [&](Chainstate* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
|
||||
|
@ -93,7 +98,7 @@ static ChainstateLoadResult CompleteChainstateInitialization(
|
|||
/*should_wipe=*/options.wipe_chainstate_db);
|
||||
} catch (dbwrapper_error& err) {
|
||||
LogError("%s\n", err.what());
|
||||
return {ChainstateLoadStatus::FAILURE, _("Error opening coins database")};
|
||||
return {util::Error{_("Error opening coins database")}, ChainstateLoadError::FAILURE};
|
||||
}
|
||||
|
||||
if (options.coins_error_cb) {
|
||||
|
@ -103,14 +108,15 @@ static ChainstateLoadResult CompleteChainstateInitialization(
|
|||
// Refuse to load unsupported database format.
|
||||
// This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
|
||||
if (chainstate->CoinsDB().NeedsUpgrade()) {
|
||||
return {ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB, _("Unsupported chainstate database format found. "
|
||||
"Please restart with -reindex-chainstate. This will "
|
||||
"rebuild the chainstate database.")};
|
||||
return {util::Error{_("Unsupported chainstate database format found. "
|
||||
"Please restart with -reindex-chainstate. This will "
|
||||
"rebuild the chainstate database.")},
|
||||
ChainstateLoadError::FAILURE_INCOMPATIBLE_DB};
|
||||
}
|
||||
|
||||
// ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate
|
||||
if (!chainstate->ReplayBlocks()) {
|
||||
return {ChainstateLoadStatus::FAILURE, _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.")};
|
||||
return {util::Error{_("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.")}, ChainstateLoadError::FAILURE};
|
||||
}
|
||||
|
||||
// The on-disk coinsdb is now in a good state, create the cache
|
||||
|
@ -120,7 +126,7 @@ static ChainstateLoadResult CompleteChainstateInitialization(
|
|||
if (!is_coinsview_empty(chainstate)) {
|
||||
// LoadChainTip initializes the chain based on CoinsTip()'s best block
|
||||
if (!chainstate->LoadChainTip()) {
|
||||
return {ChainstateLoadStatus::FAILURE, _("Error initializing block database")};
|
||||
return {util::Error{_("Error initializing block database")}, ChainstateLoadError::FAILURE};
|
||||
}
|
||||
assert(chainstate->m_chain.Tip() != nullptr);
|
||||
}
|
||||
|
@ -129,8 +135,8 @@ static ChainstateLoadResult CompleteChainstateInitialization(
|
|||
auto chainstates{chainman.GetAll()};
|
||||
if (std::any_of(chainstates.begin(), chainstates.end(),
|
||||
[](const Chainstate* cs) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return cs->NeedsRedownload(); })) {
|
||||
return {ChainstateLoadStatus::FAILURE, strprintf(_("Witness data for blocks after height %d requires validation. Please restart with -reindex."),
|
||||
chainman.GetConsensus().SegwitHeight)};
|
||||
return {util::Error{strprintf(_("Witness data for blocks after height %d requires validation. Please restart with -reindex."),
|
||||
chainman.GetConsensus().SegwitHeight)}, ChainstateLoadError::FAILURE};
|
||||
};
|
||||
|
||||
// Now that chainstates are loaded and we're able to flush to
|
||||
|
@ -138,12 +144,13 @@ static ChainstateLoadResult CompleteChainstateInitialization(
|
|||
// on the condition of each chainstate.
|
||||
chainman.MaybeRebalanceCaches();
|
||||
|
||||
return {ChainstateLoadStatus::SUCCESS, {}};
|
||||
return {};
|
||||
}
|
||||
|
||||
ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSizes& cache_sizes,
|
||||
const ChainstateLoadOptions& options)
|
||||
util::Result<InterruptResult, ChainstateLoadError> LoadChainstate(ChainstateManager& chainman, const CacheSizes& cache_sizes,
|
||||
const ChainstateLoadOptions& options)
|
||||
{
|
||||
util::Result<InterruptResult, ChainstateLoadError> result;
|
||||
if (!chainman.AssumedValidBlock().IsNull()) {
|
||||
LogPrintf("Assuming ancestors of block %s have valid signatures.\n", chainman.AssumedValidBlock().GetHex());
|
||||
} else {
|
||||
|
@ -173,13 +180,14 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
|
|||
if (has_snapshot && options.wipe_chainstate_db) {
|
||||
LogPrintf("[snapshot] deleting snapshot chainstate due to reindexing\n");
|
||||
if (!chainman.DeleteSnapshotChainstate()) {
|
||||
return {ChainstateLoadStatus::FAILURE_FATAL, Untranslated("Couldn't remove snapshot chainstate.")};
|
||||
result.Update({util::Error{Untranslated("Couldn't remove snapshot chainstate.")}, ChainstateLoadError::FAILURE_FATAL});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
auto [init_status, init_error] = CompleteChainstateInitialization(chainman, options);
|
||||
if (init_status != ChainstateLoadStatus::SUCCESS) {
|
||||
return {init_status, init_error};
|
||||
result.Update(CompleteChainstateInitialization(chainman, options));
|
||||
if (!result || IsInterrupted(*result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// If a snapshot chainstate was fully validated by a background chainstate during
|
||||
|
@ -197,7 +205,8 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
|
|||
} else if (snapshot_completion == SnapshotCompletionResult::SUCCESS) {
|
||||
LogPrintf("[snapshot] cleaning up unneeded background chainstate, then reinitializing\n");
|
||||
if (!chainman.ValidatedSnapshotCleanup()) {
|
||||
return {ChainstateLoadStatus::FAILURE_FATAL, Untranslated("Background chainstate cleanup failed unexpectedly.")};
|
||||
result.Update({util::Error{Untranslated("Background chainstate cleanup failed unexpectedly.")}, ChainstateLoadError::FAILURE_FATAL});
|
||||
return result;
|
||||
}
|
||||
|
||||
// Because ValidatedSnapshotCleanup() has torn down chainstates with
|
||||
|
@ -213,20 +222,22 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
|
|||
// for the fully validated chainstate.
|
||||
chainman.ActiveChainstate().ClearBlockIndexCandidates();
|
||||
|
||||
auto [init_status, init_error] = CompleteChainstateInitialization(chainman, options);
|
||||
if (init_status != ChainstateLoadStatus::SUCCESS) {
|
||||
return {init_status, init_error};
|
||||
auto result{CompleteChainstateInitialization(chainman, options)};
|
||||
if (!result || IsInterrupted(*result)) {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
return {ChainstateLoadStatus::FAILURE_FATAL, _(
|
||||
result.Update({util::Error{_(
|
||||
"UTXO snapshot failed to validate. "
|
||||
"Restart to resume normal initial block download, or try loading a different snapshot.")};
|
||||
"Restart to resume normal initial block download, or try loading a different snapshot.")},
|
||||
ChainstateLoadError::FAILURE_FATAL});
|
||||
return result;
|
||||
}
|
||||
|
||||
return {ChainstateLoadStatus::SUCCESS, {}};
|
||||
return result;
|
||||
}
|
||||
|
||||
ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const ChainstateLoadOptions& options)
|
||||
util::Result<InterruptResult, ChainstateLoadError> VerifyLoadedChainstate(ChainstateManager& chainman, const ChainstateLoadOptions& options)
|
||||
{
|
||||
auto is_coinsview_empty = [&](Chainstate* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
|
||||
return options.wipe_chainstate_db || chainstate->CoinsTip().GetBestBlock().IsNull();
|
||||
|
@ -234,36 +245,42 @@ ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const C
|
|||
|
||||
LOCK(cs_main);
|
||||
|
||||
util::Result<InterruptResult, ChainstateLoadError> result;
|
||||
for (Chainstate* chainstate : chainman.GetAll()) {
|
||||
if (!is_coinsview_empty(chainstate)) {
|
||||
const CBlockIndex* tip = chainstate->m_chain.Tip();
|
||||
if (tip && tip->nTime > GetTime() + MAX_FUTURE_BLOCK_TIME) {
|
||||
return {ChainstateLoadStatus::FAILURE, _("The block database contains a block which appears to be from the future. "
|
||||
"This may be due to your computer's date and time being set incorrectly. "
|
||||
"Only rebuild the block database if you are sure that your computer's date and time are correct")};
|
||||
result.Update({util::Error{_("The block database contains a block which appears to be from the future. "
|
||||
"This may be due to your computer's date and time being set incorrectly. "
|
||||
"Only rebuild the block database if you are sure that your computer's date and time are correct")},
|
||||
ChainstateLoadError::FAILURE});
|
||||
return result;
|
||||
}
|
||||
|
||||
VerifyDBResult result = CVerifyDB(chainman.GetNotifications()).VerifyDB(
|
||||
VerifyDBResult verify_result = CVerifyDB(chainman.GetNotifications()).VerifyDB(
|
||||
*chainstate, chainman.GetConsensus(), chainstate->CoinsDB(),
|
||||
options.check_level,
|
||||
options.check_blocks);
|
||||
switch (result) {
|
||||
switch (verify_result) {
|
||||
case VerifyDBResult::SUCCESS:
|
||||
case VerifyDBResult::SKIPPED_MISSING_BLOCKS:
|
||||
break;
|
||||
case VerifyDBResult::INTERRUPTED:
|
||||
return {ChainstateLoadStatus::INTERRUPTED, _("Block verification was interrupted")};
|
||||
result.Update(Interrupted{});
|
||||
return result;
|
||||
case VerifyDBResult::CORRUPTED_BLOCK_DB:
|
||||
return {ChainstateLoadStatus::FAILURE, _("Corrupted block database detected")};
|
||||
result.Update({util::Error{_("Corrupted block database detected")}, ChainstateLoadError::FAILURE});
|
||||
return result;
|
||||
case VerifyDBResult::SKIPPED_L3_CHECKS:
|
||||
if (options.require_full_verification) {
|
||||
return {ChainstateLoadStatus::FAILURE_INSUFFICIENT_DBCACHE, _("Insufficient dbcache for block verification")};
|
||||
result.Update({util::Error{_("Insufficient dbcache for block verification")}, ChainstateLoadError::FAILURE_INSUFFICIENT_DBCACHE});
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
} // no default case, so the compiler can warn about missing cases
|
||||
}
|
||||
}
|
||||
|
||||
return {ChainstateLoadStatus::SUCCESS, {}};
|
||||
return result;
|
||||
}
|
||||
} // namespace node
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#ifndef BITCOIN_NODE_CHAINSTATE_H
|
||||
#define BITCOIN_NODE_CHAINSTATE_H
|
||||
|
||||
#include <kernel/notifications_interface.h>
|
||||
#include <util/result.h>
|
||||
#include <util/translation.h>
|
||||
#include <validation.h>
|
||||
|
||||
|
@ -41,34 +43,16 @@ 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,
|
||||
enum class ChainstateLoadError {
|
||||
FAILURE, //!< Generic failure which reindexing may fix
|
||||
FAILURE_FATAL, //!< Fatal error which should not prompt to reindex
|
||||
FAILURE_INCOMPATIBLE_DB,
|
||||
FAILURE_INSUFFICIENT_DBCACHE,
|
||||
INTERRUPTED,
|
||||
};
|
||||
|
||||
//! Chainstate load status code and optional error string.
|
||||
using ChainstateLoadResult = std::tuple<ChainstateLoadStatus, bilingual_str>;
|
||||
|
||||
/** This sequence can have 4 types of outcomes:
|
||||
*
|
||||
* 1. Success
|
||||
* 2. Shutdown requested
|
||||
* - nothing failed but a shutdown was triggered in the middle of the
|
||||
* sequence
|
||||
* 3. Soft failure
|
||||
* - a failure that might be recovered from with a reindex
|
||||
* 4. Hard failure
|
||||
* - a failure that definitively cannot be recovered from with a reindex
|
||||
*
|
||||
* LoadChainstate returns a (status code, error string) tuple.
|
||||
*/
|
||||
ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const kernel::CacheSizes& cache_sizes,
|
||||
const ChainstateLoadOptions& options);
|
||||
ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const ChainstateLoadOptions& options);
|
||||
util::Result<kernel::InterruptResult, ChainstateLoadError> LoadChainstate(ChainstateManager& chainman, const kernel::CacheSizes& cache_sizes,
|
||||
const ChainstateLoadOptions& options);
|
||||
util::Result<kernel::InterruptResult, ChainstateLoadError> VerifyLoadedChainstate(ChainstateManager& chainman, const ChainstateLoadOptions& options);
|
||||
} // namespace node
|
||||
|
||||
#endif // BITCOIN_NODE_CHAINSTATE_H
|
||||
|
|
|
@ -290,11 +290,11 @@ void ChainTestingSetup::LoadVerifyActivateChainstate()
|
|||
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_kernel_cache_sizes, options);
|
||||
assert(status == node::ChainstateLoadStatus::SUCCESS);
|
||||
auto load_result{LoadChainstate(chainman, m_kernel_cache_sizes, options)};
|
||||
Assert(load_result);
|
||||
|
||||
std::tie(status, error) = VerifyLoadedChainstate(chainman, options);
|
||||
assert(status == node::ChainstateLoadStatus::SUCCESS);
|
||||
auto verify_result{VerifyLoadedChainstate(chainman, options)};
|
||||
Assert(verify_result);
|
||||
|
||||
BlockValidationState state;
|
||||
if (!chainman.ActiveChainstate().ActivateBestChain(state)) {
|
||||
|
|
Loading…
Add table
Reference in a new issue