refactor: wallet: move error handling to PopulateWalletFromDB()
This commit is contained in:
1 parent
0972785fd7
commit
a48e23f566
5 files changed
+53
-76
No files matched your search
@@ -306,7 +306,7 @@ void TestLoadWallet(const std::string& name, DatabaseFormat format, std::functio
|
|||||||
std::vector<bilingual_str> warnings;
|
std::vector<bilingual_str> warnings;
|
||||||
auto database{MakeWalletDatabase(name, options, status, error)};
|
auto database{MakeWalletDatabase(name, options, status, error)};
|
||||||
auto wallet{std::make_shared<CWallet>(chain.get(), "", std::move(database))};
|
auto wallet{std::make_shared<CWallet>(chain.get(), "", std::move(database))};
|
||||||
BOOST_CHECK_EQUAL(wallet->PopulateWalletFromDB(), DBErrors::LOAD_OK);
|
BOOST_CHECK_EQUAL(wallet->PopulateWalletFromDB(error, warnings), DBErrors::LOAD_OK);
|
||||||
WITH_LOCK(wallet->cs_wallet, f(wallet));
|
WITH_LOCK(wallet->cs_wallet, f(wallet));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ public:
|
|||||||
|
|
||||||
BOOST_FIXTURE_TEST_CASE(wallet_load_descriptors, TestingSetup)
|
BOOST_FIXTURE_TEST_CASE(wallet_load_descriptors, TestingSetup)
|
||||||
{
|
{
|
||||||
|
bilingual_str _error;
|
||||||
|
std::vector<bilingual_str> _warnings;
|
||||||
std::unique_ptr<WalletDatabase> database = CreateMockableWalletDatabase();
|
std::unique_ptr<WalletDatabase> database = CreateMockableWalletDatabase();
|
||||||
{
|
{
|
||||||
// Write unknown active descriptor
|
// Write unknown active descriptor
|
||||||
@@ -52,7 +54,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_load_descriptors, TestingSetup)
|
|||||||
{
|
{
|
||||||
// Now try to load the wallet and verify the error.
|
// Now try to load the wallet and verify the error.
|
||||||
const std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(database)));
|
const std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(database)));
|
||||||
BOOST_CHECK_EQUAL(wallet->PopulateWalletFromDB(), DBErrors::UNKNOWN_DESCRIPTOR);
|
BOOST_CHECK_EQUAL(wallet->PopulateWalletFromDB(_error, _warnings), DBErrors::UNKNOWN_DESCRIPTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 2
|
// Test 2
|
||||||
@@ -78,7 +80,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_load_descriptors, TestingSetup)
|
|||||||
{
|
{
|
||||||
// Now try to load the wallet and verify the error.
|
// Now try to load the wallet and verify the error.
|
||||||
const std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(database)));
|
const std::shared_ptr<CWallet> wallet(new CWallet(m_node.chain.get(), "", std::move(database)));
|
||||||
BOOST_CHECK_EQUAL(wallet->PopulateWalletFromDB(), DBErrors::CORRUPT);
|
BOOST_CHECK_EQUAL(wallet->PopulateWalletFromDB(_error, _warnings), DBErrors::CORRUPT);
|
||||||
BOOST_CHECK(found); // The error must be logged
|
BOOST_CHECK(found); // The error must be logged
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-46
@@ -2290,7 +2290,7 @@ void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DBErrors CWallet::PopulateWalletFromDB()
|
DBErrors CWallet::PopulateWalletFromDB(bilingual_str& error, std::vector<bilingual_str>& warnings)
|
||||||
{
|
{
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
|
|
||||||
@@ -2312,6 +2312,36 @@ DBErrors CWallet::PopulateWalletFromDB()
|
|||||||
assert(m_internal_spk_managers.empty());
|
assert(m_internal_spk_managers.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nLoadWalletRet != DBErrors::LOAD_OK) {
|
||||||
|
const auto wallet_file = m_database->Filename();
|
||||||
|
if (nLoadWalletRet == DBErrors::CORRUPT) {
|
||||||
|
error = strprintf(_("Error loading %s: Wallet corrupted"), wallet_file);
|
||||||
|
} else if (nLoadWalletRet == DBErrors::NONCRITICAL_ERROR) {
|
||||||
|
warnings.push_back(strprintf(_("Error reading %s! All keys read correctly, but transaction data"
|
||||||
|
" or address metadata may be missing or incorrect."),
|
||||||
|
wallet_file));
|
||||||
|
} else if (nLoadWalletRet == DBErrors::TOO_NEW) {
|
||||||
|
error = strprintf(_("Error loading %s: Wallet requires newer version of %s"), wallet_file, CLIENT_NAME);
|
||||||
|
} else if (nLoadWalletRet == DBErrors::EXTERNAL_SIGNER_SUPPORT_REQUIRED) {
|
||||||
|
error = strprintf(_("Error loading %s: External signer wallet being loaded without external signer support compiled"), wallet_file);
|
||||||
|
} else if (nLoadWalletRet == DBErrors::NEED_REWRITE) {
|
||||||
|
error = strprintf(_("Wallet needed to be rewritten: restart %s to complete"), CLIENT_NAME);
|
||||||
|
} else if (nLoadWalletRet == DBErrors::NEED_RESCAN) {
|
||||||
|
warnings.push_back(strprintf(_("Error reading %s! Transaction data may be missing or incorrect."
|
||||||
|
" Rescanning wallet."), wallet_file));
|
||||||
|
} else if (nLoadWalletRet == DBErrors::UNKNOWN_DESCRIPTOR) {
|
||||||
|
error = strprintf(_("Unrecognized descriptor found. Loading wallet %s\n\n"
|
||||||
|
"The wallet might have been created on a newer version.\n"
|
||||||
|
"Please try running the latest software version.\n"), wallet_file);
|
||||||
|
} else if (nLoadWalletRet == DBErrors::UNEXPECTED_LEGACY_ENTRY) {
|
||||||
|
error = strprintf(_("Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n\n"
|
||||||
|
"The wallet might have been tampered with or created with malicious intent.\n"), wallet_file);
|
||||||
|
} else if (nLoadWalletRet == DBErrors::LEGACY_WALLET) {
|
||||||
|
error = strprintf(_("Error loading %s: Wallet is a legacy wallet. Please migrate to a descriptor wallet using the migration tool (migratewallet RPC)."), wallet_file);
|
||||||
|
} else {
|
||||||
|
error = strprintf(_("Error loading %s"), wallet_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
return nLoadWalletRet;
|
return nLoadWalletRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2854,51 +2884,10 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
|
|||||||
walletInstance->m_notify_tx_changed_script = args.GetArg("-walletnotify", "");
|
walletInstance->m_notify_tx_changed_script = args.GetArg("-walletnotify", "");
|
||||||
|
|
||||||
// Load wallet
|
// Load wallet
|
||||||
bool rescan_required = false;
|
auto nLoadWalletRet = walletInstance->PopulateWalletFromDB(error, warnings);
|
||||||
DBErrors nLoadWalletRet = walletInstance->PopulateWalletFromDB();
|
bool rescan_required = nLoadWalletRet == DBErrors::NEED_RESCAN;
|
||||||
if (nLoadWalletRet != DBErrors::LOAD_OK) {
|
if (nLoadWalletRet != DBErrors::LOAD_OK && nLoadWalletRet != DBErrors::NONCRITICAL_ERROR && !rescan_required) {
|
||||||
if (nLoadWalletRet == DBErrors::CORRUPT) {
|
return nullptr;
|
||||||
error = strprintf(_("Error loading %s: Wallet corrupted"), walletFile);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
else if (nLoadWalletRet == DBErrors::NONCRITICAL_ERROR)
|
|
||||||
{
|
|
||||||
warnings.push_back(strprintf(_("Error reading %s! All keys read correctly, but transaction data"
|
|
||||||
" or address metadata may be missing or incorrect."),
|
|
||||||
walletFile));
|
|
||||||
}
|
|
||||||
else if (nLoadWalletRet == DBErrors::TOO_NEW) {
|
|
||||||
error = strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, CLIENT_NAME);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
else if (nLoadWalletRet == DBErrors::EXTERNAL_SIGNER_SUPPORT_REQUIRED) {
|
|
||||||
error = strprintf(_("Error loading %s: External signer wallet being loaded without external signer support compiled"), walletFile);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
else if (nLoadWalletRet == DBErrors::NEED_REWRITE)
|
|
||||||
{
|
|
||||||
error = strprintf(_("Wallet needed to be rewritten: restart %s to complete"), CLIENT_NAME);
|
|
||||||
return nullptr;
|
|
||||||
} else if (nLoadWalletRet == DBErrors::NEED_RESCAN) {
|
|
||||||
warnings.push_back(strprintf(_("Error reading %s! Transaction data may be missing or incorrect."
|
|
||||||
" Rescanning wallet."), walletFile));
|
|
||||||
rescan_required = true;
|
|
||||||
} else if (nLoadWalletRet == DBErrors::UNKNOWN_DESCRIPTOR) {
|
|
||||||
error = strprintf(_("Unrecognized descriptor found. Loading wallet %s\n\n"
|
|
||||||
"The wallet might have been created on a newer version.\n"
|
|
||||||
"Please try running the latest software version.\n"), walletFile);
|
|
||||||
return nullptr;
|
|
||||||
} else if (nLoadWalletRet == DBErrors::UNEXPECTED_LEGACY_ENTRY) {
|
|
||||||
error = strprintf(_("Unexpected legacy entry in descriptor wallet found. Loading wallet %s\n\n"
|
|
||||||
"The wallet might have been tampered with or created with malicious intent.\n"), walletFile);
|
|
||||||
return nullptr;
|
|
||||||
} else if (nLoadWalletRet == DBErrors::LEGACY_WALLET) {
|
|
||||||
error = strprintf(_("Error loading %s: Wallet is a legacy wallet. Please migrate to a descriptor wallet using the migration tool (migratewallet RPC)."), walletFile);
|
|
||||||
return nullptr;
|
|
||||||
} else {
|
|
||||||
error = strprintf(_("Error loading %s"), walletFile);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This wallet is in its first run if there are no ScriptPubKeyMans and it isn't blank or no privkeys
|
// This wallet is in its first run if there are no ScriptPubKeyMans and it isn't blank or no privkeys
|
||||||
|
|||||||
+1
-1
@@ -797,7 +797,7 @@ public:
|
|||||||
bool IsFromMe(const CTransaction& tx) const;
|
bool IsFromMe(const CTransaction& tx) const;
|
||||||
CAmount GetDebit(const CTransaction& tx) const;
|
CAmount GetDebit(const CTransaction& tx) const;
|
||||||
|
|
||||||
DBErrors PopulateWalletFromDB();
|
DBErrors PopulateWalletFromDB(bilingual_str& error, std::vector<bilingual_str>& warnings);
|
||||||
|
|
||||||
/** Erases the provided transactions from the wallet. */
|
/** Erases the provided transactions from the wallet. */
|
||||||
util::Result<void> RemoveTxs(std::vector<Txid>& txs_to_remove) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
util::Result<void> RemoveTxs(std::vector<Txid>& txs_to_remove) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||||
|
|||||||
+12
-26
@@ -2,8 +2,6 @@
|
|||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include <bitcoin-build-config.h> // IWYU pragma: keep
|
|
||||||
|
|
||||||
#include <wallet/wallettool.h>
|
#include <wallet/wallettool.h>
|
||||||
|
|
||||||
#include <common/args.h>
|
#include <common/args.h>
|
||||||
@@ -44,6 +42,7 @@ static std::shared_ptr<CWallet> MakeWallet(const std::string& name, const fs::pa
|
|||||||
{
|
{
|
||||||
DatabaseStatus status;
|
DatabaseStatus status;
|
||||||
bilingual_str error;
|
bilingual_str error;
|
||||||
|
std::vector<bilingual_str> warnings;
|
||||||
std::unique_ptr<WalletDatabase> database = MakeDatabase(path, options, status, error);
|
std::unique_ptr<WalletDatabase> database = MakeDatabase(path, options, status, error);
|
||||||
if (!database) {
|
if (!database) {
|
||||||
tfm::format(std::cerr, "%s\n", error.original);
|
tfm::format(std::cerr, "%s\n", error.original);
|
||||||
@@ -54,35 +53,22 @@ static std::shared_ptr<CWallet> MakeWallet(const std::string& name, const fs::pa
|
|||||||
std::shared_ptr<CWallet> wallet_instance{new CWallet(/*chain=*/nullptr, name, std::move(database)), WalletToolReleaseWallet};
|
std::shared_ptr<CWallet> wallet_instance{new CWallet(/*chain=*/nullptr, name, std::move(database)), WalletToolReleaseWallet};
|
||||||
DBErrors load_wallet_ret;
|
DBErrors load_wallet_ret;
|
||||||
try {
|
try {
|
||||||
load_wallet_ret = wallet_instance->PopulateWalletFromDB();
|
load_wallet_ret = wallet_instance->PopulateWalletFromDB(error, warnings);
|
||||||
} catch (const std::runtime_error&) {
|
} catch (const std::runtime_error&) {
|
||||||
tfm::format(std::cerr, "Error loading %s. Is wallet being used by another process?\n", name);
|
tfm::format(std::cerr, "Error loading %s. Is wallet being used by another process?\n", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (load_wallet_ret != DBErrors::LOAD_OK) {
|
if (!error.empty()) {
|
||||||
if (load_wallet_ret == DBErrors::CORRUPT) {
|
tfm::format(std::cerr, "%s", error.original);
|
||||||
tfm::format(std::cerr, "Error loading %s: Wallet corrupted", name);
|
}
|
||||||
return nullptr;
|
|
||||||
} else if (load_wallet_ret == DBErrors::NONCRITICAL_ERROR) {
|
for (const auto &warning : warnings) {
|
||||||
tfm::format(std::cerr, "Error reading %s! All keys read correctly, but transaction data"
|
tfm::format(std::cerr, "%s", warning.original);
|
||||||
" or address book entries might be missing or incorrect.",
|
}
|
||||||
name);
|
|
||||||
} else if (load_wallet_ret == DBErrors::TOO_NEW) {
|
if (load_wallet_ret != DBErrors::LOAD_OK && load_wallet_ret != DBErrors::NONCRITICAL_ERROR && load_wallet_ret != DBErrors::NEED_RESCAN) {
|
||||||
tfm::format(std::cerr, "Error loading %s: Wallet requires newer version of %s",
|
return nullptr;
|
||||||
name, CLIENT_NAME);
|
|
||||||
return nullptr;
|
|
||||||
} else if (load_wallet_ret == DBErrors::NEED_REWRITE) {
|
|
||||||
tfm::format(std::cerr, "Wallet needed to be rewritten: restart %s to complete", CLIENT_NAME);
|
|
||||||
return nullptr;
|
|
||||||
} else if (load_wallet_ret == DBErrors::NEED_RESCAN) {
|
|
||||||
tfm::format(std::cerr, "Error reading %s! Some transaction data might be missing or"
|
|
||||||
" incorrect. Wallet requires a rescan.",
|
|
||||||
name);
|
|
||||||
} else {
|
|
||||||
tfm::format(std::cerr, "Error loading %s", name);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.require_create) WalletCreate(wallet_instance.get(), options.create_flags);
|
if (options.require_create) WalletCreate(wallet_instance.get(), options.create_flags);
|
||||||
|
|||||||
Reference in new issue
Block a user