diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -2482,7 +2482,8 @@ } } - if (status == node::ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB || + if (status == node::ChainstateLoadStatus::FAILURE_FATAL || + status == node::ChainstateLoadStatus::FAILURE_INCOMPATIBLE_DB || status == node::ChainstateLoadStatus::FAILURE_INSUFFICIENT_DBCACHE) { return InitError(error); diff --git a/src/node/chainstate.h b/src/node/chainstate.h --- a/src/node/chainstate.h +++ b/src/node/chainstate.h @@ -43,7 +43,10 @@ //! and exit cleanly in the interrupted case. enum class ChainstateLoadStatus { SUCCESS, + //! Generic failure which reindexing may fix FAILURE, + //! Fatal error which should not prompt to reindex + FAILURE_FATAL, FAILURE_INCOMPATIBLE_DB, FAILURE_INSUFFICIENT_DBCACHE, INTERRUPTED diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -221,7 +221,9 @@ LogPrintf("[snapshot] cleaning up unneeded background chainstate, then " "reinitializing\n"); if (!chainman.ValidatedSnapshotCleanup()) { - AbortNode("Background chainstate cleanup failed unexpectedly."); + return {ChainstateLoadStatus::FAILURE_FATAL, + Untranslated( + "Background chainstate cleanup failed unexpectedly.")}; } // Because ValidatedSnapshotCleanup() has torn down chainstates with diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -37,6 +37,7 @@ #include // For CTxMemPool::cs #include #include +#include #include #include @@ -1086,7 +1087,8 @@ * In case of an invalid snapshot, rename the coins leveldb directory so * that it can be examined for issue diagnosis. */ - void InvalidateCoinsDBOnDisk() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + [[nodiscard]] util::Result InvalidateCoinsDBOnDisk() + EXCLUSIVE_LOCKS_REQUIRED(::cs_main); friend ChainstateManager; }; diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -6227,7 +6227,7 @@ "the chain height from %d to %d. On the next restart, the node " "will resume syncing from %d without using any snapshot data. " "Please report this incident to %s, including how you obtained " - "the snapshot. The invalid snapshot chainstate has been left on " + "the snapshot. The invalid snapshot chainstate will be left on " "disk in case it is helpful in diagnosing the issue that caused " "this error."), PACKAGE_NAME, snapshot_tip_height, snapshot_base_height, @@ -6242,7 +6242,11 @@ assert(!this->IsUsable(m_snapshot_chainstate.get())); assert(this->IsUsable(m_ibd_chainstate.get())); - m_snapshot_chainstate->InvalidateCoinsDBOnDisk(); + auto rename_result = m_snapshot_chainstate->InvalidateCoinsDBOnDisk(); + if (!rename_result) { + user_error = strprintf(Untranslated("%s\n%s"), user_error, + util::ErrorString(rename_result)); + } shutdown_fnc(user_error); }; @@ -6439,7 +6443,7 @@ return *m_snapshot_chainstate; } -void Chainstate::InvalidateCoinsDBOnDisk() { +util::Result Chainstate::InvalidateCoinsDBOnDisk() { AssertLockHeld(::cs_main); // Should never be called on a non-snapshot chainstate. assert(m_from_snapshot_blockhash); @@ -6468,14 +6472,15 @@ LogPrintf("%s: error renaming file '%s' -> '%s': %s\n", __func__, src_str, dest_str, e.what()); - AbortNode(strprintf("Rename of '%s' -> '%s' failed. " - "You should resolve this by manually moving or " - "deleting the invalid " - "snapshot directory %s, otherwise you will " - "encounter the same error again " - "on the next startup.", - src_str, dest_str, src_str)); - } + return util::Error{strprintf(_("Rename of '%s' -> '%s' failed. " + "You should resolve this by manually " + "moving or deleting the invalid " + "snapshot directory %s, otherwise you " + "will encounter the same error again " + "on the next startup."), + src_str, dest_str, src_str)}; + } + return {}; } const CBlockIndex *ChainstateManager::GetSnapshotBaseBlock() const {