Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add util::ResultPtr class #26022

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
refactor: Use util::Result class in LoadChainstate and VerifyLoadedCh…
…ainstate
  • Loading branch information
ryanofsky committed Dec 6, 2024
commit 2dd48496a4877f1ba9065fed9db8d7c498fa3404
8 changes: 4 additions & 4 deletions src/bitcoin-chainstate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,13 @@ int main(int argc, char* argv[])
cache_sizes.coins_db = 2 << 22;
cache_sizes.coins = (450 << 20) - (2 << 20) - (2 << 22);
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;
}
Expand Down
40 changes: 21 additions & 19 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,12 @@
using common::AmountErrMsg;
using common::InvalidPortErrMsg;
using common::ResolveErrMsg;

using kernel::InterruptResult;
using node::ApplyArgsManOptions;
using node::BlockManager;
using node::CacheSizes;
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;
Expand Down Expand Up @@ -1173,7 +1172,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,
Expand All @@ -1189,7 +1188,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{
Expand All @@ -1208,7 +1207,7 @@ static ChainstateLoadResult InitAndLoadChainstate(
try {
node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown_signal), chainman_opts, blockman_opts);
} 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;
// This is defined and set here instead of inline in validation.h to avoid a hard
Expand Down Expand Up @@ -1246,27 +1245,29 @@ static ChainstateLoadResult InitAndLoadChainstate(
};
uiInterface.InitMessage(_("Loading block index…").translated);
const auto load_block_index_start_time{SteadyClock::now()};
auto catch_exceptions = [](auto&& f) {
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…").translated);
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)) {
LogPrintf(" block index %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - load_block_index_start_time));
}
}
return {status, error};
return result;
};

bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
Expand Down Expand Up @@ -1623,14 +1624,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,
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.",
Expand All @@ -1642,15 +1644,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,
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
Expand Down
Loading