wallet: Avoid translating RPC errors when loading wallets

Common errors and warnings should be translated when displayed in the
GUI, but not translated when displayed elsewhere. The wallet method
CreateWalletFromFile does not know its caller, so this commit changes it
to return a bilingual_str to the caller.
This commit is contained in:
MarcoFalke 2019-08-19 18:12:35 -04:00
parent 608359b071
commit fae51a5c6f
No known key found for this signature in database
GPG key ID: CE2B75697E69A548
18 changed files with 149 additions and 121 deletions

View file

@ -8,6 +8,7 @@
class CWallet;
enum class WalletCreationStatus;
struct bilingual_str;
namespace interfaces {
class Chain;
@ -72,12 +73,12 @@ std::vector<std::shared_ptr<CWallet>> GetWallets()
throw std::logic_error("Wallet function called in non-wallet build.");
}
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::vector<std::string>& warnings)
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
throw std::logic_error("Wallet function called in non-wallet build.");
}
WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::vector<std::string>& warnings, std::shared_ptr<CWallet>& result)
WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, std::shared_ptr<CWallet>& result)
{
throw std::logic_error("Wallet function called in non-wallet build.");
}

View file

@ -43,8 +43,8 @@ class CWallet;
fs::path GetWalletDir();
std::vector<fs::path> ListWalletDir();
std::vector<std::shared_ptr<CWallet>> GetWallets();
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::vector<std::string>& warnings);
WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::vector<std::string>& warnings, std::shared_ptr<CWallet>& result);
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings);
WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, std::shared_ptr<CWallet>& result);
std::unique_ptr<interfaces::Handler> HandleLoadWallet(interfaces::Node::LoadWalletFn load_wallet);
namespace interfaces {
@ -259,11 +259,11 @@ public:
}
return wallets;
}
std::unique_ptr<Wallet> loadWallet(const std::string& name, std::string& error, std::vector<std::string>& warnings) override
std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) override
{
return MakeWallet(LoadWallet(*m_context.chain, name, error, warnings));
}
std::unique_ptr<Wallet> createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::vector<std::string>& warnings, WalletCreationStatus& status) override
std::unique_ptr<Wallet> createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, WalletCreationStatus& status) override
{
std::shared_ptr<CWallet> wallet;
status = CreateWallet(*m_context.chain, passphrase, wallet_creation_flags, name, error, warnings, wallet);

View file

@ -27,9 +27,10 @@ class Coin;
class RPCTimerInterface;
class UniValue;
class proxyType;
enum class WalletCreationStatus;
struct CNodeStateStats;
struct NodeContext;
enum class WalletCreationStatus;
struct bilingual_str;
namespace interfaces {
class Handler;
@ -201,10 +202,10 @@ public:
//! Attempts to load a wallet from file or directory.
//! The loaded wallet is also notified to handlers previously registered
//! with handleLoadWallet.
virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, std::string& error, std::vector<std::string>& warnings) = 0;
virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;
//! Create a wallet from file
virtual std::unique_ptr<Wallet> createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::vector<std::string>& warnings, WalletCreationStatus& status) = 0;
virtual std::unique_ptr<Wallet> createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, WalletCreationStatus& status) = 0;
//! Register handler for init messages.
using InitMessageFn = std::function<void(const std::string& message)>;

View file

@ -14,6 +14,7 @@
#include <interfaces/handler.h>
#include <interfaces/node.h>
#include <util/string.h>
#include <util/translation.h>
#include <wallet/wallet.h>
#include <algorithm>
@ -244,10 +245,10 @@ void CreateWalletActivity::finish()
{
destroyProgressDialog();
if (!m_error_message.empty()) {
QMessageBox::critical(m_parent_widget, tr("Create wallet failed"), QString::fromStdString(m_error_message));
if (!m_error_message.original.empty()) {
QMessageBox::critical(m_parent_widget, tr("Create wallet failed"), QString::fromStdString(m_error_message.translated));
} else if (!m_warning_message.empty()) {
QMessageBox::warning(m_parent_widget, tr("Create wallet warning"), QString::fromStdString(Join(m_warning_message, "\n")));
QMessageBox::warning(m_parent_widget, tr("Create wallet warning"), QString::fromStdString(Join(m_warning_message, "\n", OpTranslated)));
}
if (m_wallet_model) Q_EMIT created(m_wallet_model);
@ -285,10 +286,10 @@ void OpenWalletActivity::finish()
{
destroyProgressDialog();
if (!m_error_message.empty()) {
QMessageBox::critical(m_parent_widget, tr("Open wallet failed"), QString::fromStdString(m_error_message));
if (!m_error_message.original.empty()) {
QMessageBox::critical(m_parent_widget, tr("Open wallet failed"), QString::fromStdString(m_error_message.translated));
} else if (!m_warning_message.empty()) {
QMessageBox::warning(m_parent_widget, tr("Open wallet warning"), QString::fromStdString(Join(m_warning_message, "\n")));
QMessageBox::warning(m_parent_widget, tr("Open wallet warning"), QString::fromStdString(Join(m_warning_message, "\n", OpTranslated)));
}
if (m_wallet_model) Q_EMIT opened(m_wallet_model);

View file

@ -8,6 +8,7 @@
#include <qt/sendcoinsrecipient.h>
#include <support/allocators/secure.h>
#include <sync.h>
#include <util/translation.h>
#include <map>
#include <memory>
@ -104,8 +105,8 @@ protected:
QWidget* const m_parent_widget;
QProgressDialog* m_progress_dialog{nullptr};
WalletModel* m_wallet_model{nullptr};
std::string m_error_message;
std::vector<std::string> m_warning_message;
bilingual_str m_error_message;
std::vector<bilingual_str> m_warning_message;
};

View file

@ -18,6 +18,20 @@ struct bilingual_str {
std::string translated;
};
inline bilingual_str operator+(const bilingual_str& lhs, const bilingual_str& rhs)
{
return bilingual_str{
lhs.original + rhs.original,
lhs.translated + rhs.translated};
}
/** Mark a bilingual_str as untranslated */
inline static bilingual_str Untranslated(std::string original) { return {original, original}; }
/** Unary operator to return the original */
inline static std::string OpOriginal(const bilingual_str& b) { return b.original; }
/** Unary operator to return the translation */
inline static std::string OpTranslated(const bilingual_str& b) { return b.translated; }
namespace tinyformat {
template <typename... Args>
bilingual_str format(const bilingual_str& fmt, const Args&... args)

View file

@ -393,7 +393,7 @@ bool BerkeleyBatch::Recover(const fs::path& file_path, void *callbackDataIn, boo
return fSuccess;
}
bool BerkeleyBatch::VerifyEnvironment(const fs::path& file_path, std::string& errorStr)
bool BerkeleyBatch::VerifyEnvironment(const fs::path& file_path, bilingual_str& errorStr)
{
std::string walletFile;
std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, walletFile);
@ -403,14 +403,14 @@ bool BerkeleyBatch::VerifyEnvironment(const fs::path& file_path, std::string& er
LogPrintf("Using wallet %s\n", file_path.string());
if (!env->Open(true /* retry */)) {
errorStr = strprintf(_("Error initializing wallet database environment %s!").translated, walletDir);
errorStr = strprintf(_("Error initializing wallet database environment %s!"), walletDir);
return false;
}
return true;
}
bool BerkeleyBatch::VerifyDatabaseFile(const fs::path& file_path, std::vector<std::string>& warnings, std::string& errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc)
bool BerkeleyBatch::VerifyDatabaseFile(const fs::path& file_path, std::vector<bilingual_str>& warnings, bilingual_str& errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc)
{
std::string walletFile;
std::shared_ptr<BerkeleyEnvironment> env = GetWalletEnv(file_path, walletFile);
@ -425,12 +425,12 @@ bool BerkeleyBatch::VerifyDatabaseFile(const fs::path& file_path, std::vector<st
warnings.push_back(strprintf(_("Warning: Wallet file corrupt, data salvaged!"
" Original %s saved as %s in %s; if"
" your balance or transactions are incorrect you should"
" restore from a backup.").translated,
" restore from a backup."),
walletFile, backup_filename, walletDir));
}
if (r == BerkeleyEnvironment::VerifyResult::RECOVER_FAIL)
{
errorStr = strprintf(_("%s corrupt, salvage failed").translated, walletFile);
errorStr = strprintf(_("%s corrupt, salvage failed"), walletFile);
return false;
}
}

View file

@ -21,6 +21,8 @@
#include <db_cxx.h>
struct bilingual_str;
static const unsigned int DEFAULT_WALLET_DBLOGSIZE = 100;
static const bool DEFAULT_WALLET_PRIVDB = true;
@ -242,9 +244,9 @@ public:
ideal to be called periodically */
static bool PeriodicFlush(BerkeleyDatabase& database);
/* verifies the database environment */
static bool VerifyEnvironment(const fs::path& file_path, std::string& errorStr);
static bool VerifyEnvironment(const fs::path& file_path, bilingual_str& errorStr);
/* verifies the database file */
static bool VerifyDatabaseFile(const fs::path& file_path, std::vector<std::string>& warnings, std::string& errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc);
static bool VerifyDatabaseFile(const fs::path& file_path, std::vector<bilingual_str>& warnings, bilingual_str& errorStr, BerkeleyEnvironment::recoverFunc_type recoverFunc);
template <typename K, typename T>
bool Read(const K& key, T& value)

View file

@ -53,12 +53,14 @@ bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wal
return false;
}
std::string error_string;
std::vector<std::string> warnings;
bilingual_str error_string;
std::vector<bilingual_str> warnings;
bool verify_success = CWallet::Verify(chain, location, salvage_wallet, error_string, warnings);
if (!error_string.empty()) chain.initError(error_string);
if (!warnings.empty()) chain.initWarning(Join(warnings, "\n"));
if (!verify_success) return false;
if (!warnings.empty()) chain.initWarning(Join(warnings, "\n", OpTranslated));
if (!verify_success) {
chain.initError(error_string.translated);
return false;
}
}
return true;
@ -68,12 +70,12 @@ bool LoadWallets(interfaces::Chain& chain, const std::vector<std::string>& walle
{
try {
for (const std::string& walletFile : wallet_files) {
std::string error;
std::vector<std::string> warnings;
bilingual_str error;
std::vector<bilingual_str> warnings;
std::shared_ptr<CWallet> pwallet = CWallet::CreateWalletFromFile(chain, WalletLocation(walletFile), error, warnings);
if (!warnings.empty()) chain.initWarning(Join(warnings, "\n"));
if (!warnings.empty()) chain.initWarning(Join(warnings, "\n", OpTranslated));
if (!pwallet) {
chain.initError(error);
chain.initError(error.translated);
return false;
}
AddWallet(pwallet);

View file

@ -23,6 +23,7 @@
#include <util/moneystr.h>
#include <util/string.h>
#include <util/system.h>
#include <util/translation.h>
#include <util/url.h>
#include <util/vector.h>
#include <wallet/coincontrol.h>
@ -2589,14 +2590,14 @@ static UniValue loadwallet(const JSONRPCRequest& request)
}
}
std::string error;
std::vector<std::string> warning;
std::shared_ptr<CWallet> const wallet = LoadWallet(*g_rpc_chain, location, error, warning);
if (!wallet) throw JSONRPCError(RPC_WALLET_ERROR, error);
bilingual_str error;
std::vector<bilingual_str> warnings;
std::shared_ptr<CWallet> const wallet = LoadWallet(*g_rpc_chain, location, error, warnings);
if (!wallet) throw JSONRPCError(RPC_WALLET_ERROR, error.original);
UniValue obj(UniValue::VOBJ);
obj.pushKV("name", wallet->GetName());
obj.pushKV("warning", Join(warning, "\n"));
obj.pushKV("warning", Join(warnings, "\n", OpOriginal));
return obj;
}
@ -2705,12 +2706,12 @@ static UniValue createwallet(const JSONRPCRequest& request)
}
SecureString passphrase;
passphrase.reserve(100);
std::vector<std::string> warnings;
std::vector<bilingual_str> warnings;
if (!request.params[3].isNull()) {
passphrase = request.params[3].get_str().c_str();
if (passphrase.empty()) {
// Empty string means unencrypted
warnings.emplace_back("Empty string given as passphrase, wallet will not be encrypted.");
warnings.emplace_back(Untranslated("Empty string given as passphrase, wallet will not be encrypted."));
}
}
@ -2721,14 +2722,14 @@ static UniValue createwallet(const JSONRPCRequest& request)
flags |= WALLET_FLAG_DESCRIPTORS;
}
std::string error;
bilingual_str error;
std::shared_ptr<CWallet> wallet;
WalletCreationStatus status = CreateWallet(*g_rpc_chain, passphrase, flags, request.params[0].get_str(), error, warnings, wallet);
switch (status) {
case WalletCreationStatus::CREATION_FAILED:
throw JSONRPCError(RPC_WALLET_ERROR, error);
throw JSONRPCError(RPC_WALLET_ERROR, error.original);
case WalletCreationStatus::ENCRYPTION_FAILED:
throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, error);
throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, error.original);
case WalletCreationStatus::SUCCESS:
break;
// no default case, so the compiler can warn about missing cases
@ -2736,7 +2737,7 @@ static UniValue createwallet(const JSONRPCRequest& request)
UniValue obj(UniValue::VOBJ);
obj.pushKV("name", wallet->GetName());
obj.pushKV("warning", Join(warnings, "\n"));
obj.pushKV("warning", Join(warnings, "\n", OpOriginal));
return obj;
}
@ -4239,12 +4240,12 @@ static UniValue upgradewallet(const JSONRPCRequest& request)
version = request.params[0].get_int();
}
std::string error;
std::vector<std::string> warnings;
bilingual_str error;
std::vector<bilingual_str> warnings;
if (!pwallet->UpgradeWallet(version, error, warnings)) {
throw JSONRPCError(RPC_WALLET_ERROR, error);
throw JSONRPCError(RPC_WALLET_ERROR, error.original);
}
return error;
return error.original;
}
UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp

View file

@ -377,10 +377,9 @@ bool LegacyScriptPubKeyMan::CanGetAddresses(bool internal) const
return keypool_has_keys;
}
bool LegacyScriptPubKeyMan::Upgrade(int prev_version, std::string& error)
bool LegacyScriptPubKeyMan::Upgrade(int prev_version, bilingual_str& error)
{
LOCK(cs_KeyStore);
error = "";
bool hd_upgrade = false;
bool split_upgrade = false;
if (m_storage.CanSupportFeature(FEATURE_HD) && !IsHDEnabled()) {
@ -405,7 +404,7 @@ bool LegacyScriptPubKeyMan::Upgrade(int prev_version, std::string& error)
// Regenerate the keypool if upgraded to HD
if (hd_upgrade) {
if (!TopUp()) {
error = _("Unable to generate keys").translated;
error = _("Unable to generate keys");
return false;
}
}

View file

@ -19,6 +19,7 @@
#include <boost/signals2/signal.hpp>
enum class OutputType;
struct bilingual_str;
// Wallet storage things that ScriptPubKeyMans need in order to be able to store things to the wallet database.
// It provides access to things that are part of the entire wallet and not specific to a ScriptPubKeyMan such as
@ -191,7 +192,7 @@ public:
virtual bool CanGetAddresses(bool internal = false) const { return false; }
/** Upgrades the wallet to the specified version */
virtual bool Upgrade(int prev_version, std::string& error) { return false; }
virtual bool Upgrade(int prev_version, bilingual_str& error) { return false; }
virtual bool HavePrivateKeys() const { return false; }
@ -343,7 +344,7 @@ public:
bool SetupGeneration(bool force = false) override;
bool Upgrade(int prev_version, std::string& error) override;
bool Upgrade(int prev_version, bilingual_str& error) override;
bool HavePrivateKeys() const override;

View file

@ -15,6 +15,7 @@
#include <rpc/server.h>
#include <test/util/logging.h>
#include <test/util/setup_common.h>
#include <util/translation.h>
#include <validation.h>
#include <wallet/coincontrol.h>
#include <wallet/test/wallet_test_fixture.h>
@ -30,8 +31,8 @@ BOOST_FIXTURE_TEST_SUITE(wallet_tests, WalletTestingSetup)
static std::shared_ptr<CWallet> TestLoadWallet(interfaces::Chain& chain)
{
std::string error;
std::vector<std::string> warnings;
bilingual_str error;
std::vector<bilingual_str> warnings;
auto wallet = CWallet::CreateWalletFromFile(chain, WalletLocation(""), error, warnings);
wallet->postInitProcess();
return wallet;

View file

@ -27,6 +27,7 @@
#include <util/fees.h>
#include <util/moneystr.h>
#include <util/rbf.h>
#include <util/string.h>
#include <util/translation.h>
#include <wallet/coincontrol.h>
#include <wallet/fees.h>
@ -149,34 +150,34 @@ void UnloadWallet(std::shared_ptr<CWallet>&& wallet)
}
}
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::vector<std::string>& warnings)
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
try {
if (!CWallet::Verify(chain, location, false, error, warnings)) {
error = "Wallet file verification failed: " + error;
error = Untranslated("Wallet file verification failed: ") + error;
return nullptr;
}
std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile(chain, location, error, warnings);
if (!wallet) {
error = "Wallet loading failed: " + error;
error = Untranslated("Wallet loading failed: ") + error;
return nullptr;
}
AddWallet(wallet);
wallet->postInitProcess();
return wallet;
} catch (const std::runtime_error& e) {
error = e.what();
error = Untranslated(e.what());
return nullptr;
}
}
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::vector<std::string>& warnings)
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
return LoadWallet(chain, WalletLocation(name), error, warnings);
}
WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::vector<std::string>& warnings, std::shared_ptr<CWallet>& result)
WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, std::shared_ptr<CWallet>& result)
{
// Indicate that the wallet is actually supposed to be blank and not just blank to make it encrypted
bool create_blank = (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET);
@ -189,39 +190,39 @@ WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString&
// Check the wallet file location
WalletLocation location(name);
if (location.Exists()) {
error = "Wallet " + location.GetName() + " already exists.";
error = strprintf(Untranslated("Wallet %s already exists."), location.GetName());
return WalletCreationStatus::CREATION_FAILED;
}
// Wallet::Verify will check if we're trying to create a wallet with a duplicate name.
if (!CWallet::Verify(chain, location, false, error, warnings)) {
error = "Wallet file verification failed: " + error;
error = Untranslated("Wallet file verification failed.") + Untranslated(" ") + error;
return WalletCreationStatus::CREATION_FAILED;
}
// Do not allow a passphrase when private keys are disabled
if (!passphrase.empty() && (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
error = "Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.";
error = Untranslated("Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.");
return WalletCreationStatus::CREATION_FAILED;
}
// Make the wallet
std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile(chain, location, error, warnings, wallet_creation_flags);
if (!wallet) {
error = "Wallet creation failed: " + error;
error = Untranslated("Wallet creation failed.") + Untranslated(" ") + error;
return WalletCreationStatus::CREATION_FAILED;
}
// Encrypt the wallet
if (!passphrase.empty() && !(wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
if (!wallet->EncryptWallet(passphrase)) {
error = "Error: Wallet created but failed to encrypt.";
error = Untranslated("Error: Wallet created but failed to encrypt.");
return WalletCreationStatus::ENCRYPTION_FAILED;
}
if (!create_blank) {
// Unlock the wallet
if (!wallet->Unlock(passphrase)) {
error = "Error: Wallet was encrypted but could not be unlocked";
error = Untranslated("Error: Wallet was encrypted but could not be unlocked");
return WalletCreationStatus::ENCRYPTION_FAILED;
}
@ -233,7 +234,7 @@ WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString&
} else {
for (auto spk_man : wallet->GetActiveScriptPubKeyMans()) {
if (!spk_man->SetupGeneration()) {
error = "Unable to generate initial keys";
error = Untranslated("Unable to generate initial keys");
return WalletCreationStatus::CREATION_FAILED;
}
}
@ -3656,7 +3657,7 @@ std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const
return values;
}
bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, bool salvage_wallet, std::string& error_string, std::vector<std::string>& warnings)
bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, bool salvage_wallet, bilingual_str& error_string, std::vector<bilingual_str>& warnings)
{
// Do some checking on wallet path. It should be either a:
//
@ -3670,17 +3671,17 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b
if (!(path_type == fs::file_not_found || path_type == fs::directory_file ||
(path_type == fs::symlink_file && fs::is_directory(wallet_path)) ||
(path_type == fs::regular_file && fs::path(location.GetName()).filename() == location.GetName()))) {
error_string = strprintf(
error_string = Untranslated(strprintf(
"Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
"database/log.?????????? files can be stored, a location where such a directory could be created, "
"or (for backwards compatibility) the name of an existing data file in -walletdir (%s)",
location.GetName(), GetWalletDir());
location.GetName(), GetWalletDir()));
return false;
}
// Make sure that the wallet path doesn't clash with an existing wallet path
if (IsWalletLoaded(wallet_path)) {
error_string = strprintf("Error loading wallet %s. Duplicate -wallet filename specified.", location.GetName());
error_string = Untranslated(strprintf("Error loading wallet %s. Duplicate -wallet filename specified.", location.GetName()));
return false;
}
@ -3692,7 +3693,7 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b
return false;
}
} catch (const fs::filesystem_error& e) {
error_string = strprintf("Error loading wallet %s. %s", location.GetName(), fsbridge::get_filesystem_error_message(e));
error_string = Untranslated(strprintf("Error loading wallet %s. %s", location.GetName(), fsbridge::get_filesystem_error_message(e)));
return false;
}
@ -3708,7 +3709,7 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b
return WalletBatch::VerifyDatabaseFile(wallet_path, warnings, error_string);
}
std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::vector<std::string>& warnings, uint64_t wallet_creation_flags)
std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error, std::vector<bilingual_str>& warnings, uint64_t wallet_creation_flags)
{
const std::string walletFile = WalletDataFilePath(location.GetPath()).string();
@ -3721,7 +3722,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
std::unique_ptr<CWallet> tempWallet = MakeUnique<CWallet>(&chain, location, WalletDatabase::Create(location.GetPath()));
DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx);
if (nZapWalletRet != DBErrors::LOAD_OK) {
error = strprintf(_("Error loading %s: Wallet corrupted").translated, walletFile);
error = strprintf(_("Error loading %s: Wallet corrupted"), walletFile);
return nullptr;
}
}
@ -3736,26 +3737,26 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
DBErrors nLoadWalletRet = walletInstance->LoadWallet(fFirstRun);
if (nLoadWalletRet != DBErrors::LOAD_OK) {
if (nLoadWalletRet == DBErrors::CORRUPT) {
error = strprintf(_("Error loading %s: Wallet corrupted").translated, walletFile);
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 book entries might be missing or incorrect.").translated,
" or address book entries might be missing or incorrect."),
walletFile));
}
else if (nLoadWalletRet == DBErrors::TOO_NEW) {
error = strprintf(_("Error loading %s: Wallet requires newer version of %s").translated, walletFile, PACKAGE_NAME);
error = strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, PACKAGE_NAME);
return nullptr;
}
else if (nLoadWalletRet == DBErrors::NEED_REWRITE)
{
error = strprintf(_("Wallet needed to be rewritten: restart %s to complete").translated, PACKAGE_NAME);
error = strprintf(_("Wallet needed to be rewritten: restart %s to complete"), PACKAGE_NAME);
return nullptr;
}
else {
error = strprintf(_("Error loading %s").translated, walletFile);
error = strprintf(_("Error loading %s"), walletFile);
return nullptr;
}
}
@ -3781,7 +3782,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
// Legacy wallets need SetupGeneration here.
for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
if (!spk_man->SetupGeneration()) {
error = _("Unable to generate initial keys").translated;
error = _("Unable to generate initial keys");
return nullptr;
}
}
@ -3791,36 +3792,36 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
walletInstance->chainStateFlushed(chain.getTipLocator());
} else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) {
// Make it impossible to disable private keys after creation
error = strprintf(_("Error loading %s: Private keys can only be disabled during creation").translated, walletFile);
error = strprintf(_("Error loading %s: Private keys can only be disabled during creation"), walletFile);
return NULL;
} else if (walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
for (auto spk_man : walletInstance->GetActiveScriptPubKeyMans()) {
if (spk_man->HavePrivateKeys()) {
warnings.push_back(strprintf(_("Warning: Private keys detected in wallet {%s} with disabled private keys").translated, walletFile));
warnings.push_back(strprintf(_("Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile));
break;
}
}
}
if (!gArgs.GetArg("-addresstype", "").empty() && !ParseOutputType(gArgs.GetArg("-addresstype", ""), walletInstance->m_default_address_type)) {
error = strprintf(_("Unknown address type '%s'").translated, gArgs.GetArg("-addresstype", ""));
error = strprintf(_("Unknown address type '%s'"), gArgs.GetArg("-addresstype", ""));
return nullptr;
}
if (!gArgs.GetArg("-changetype", "").empty() && !ParseOutputType(gArgs.GetArg("-changetype", ""), walletInstance->m_default_change_type)) {
error = strprintf(_("Unknown change type '%s'").translated, gArgs.GetArg("-changetype", ""));
error = strprintf(_("Unknown change type '%s'"), gArgs.GetArg("-changetype", ""));
return nullptr;
}
if (gArgs.IsArgSet("-mintxfee")) {
CAmount n = 0;
if (!ParseMoney(gArgs.GetArg("-mintxfee", ""), n) || 0 == n) {
error = AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", "")).translated;
error = AmountErrMsg("mintxfee", gArgs.GetArg("-mintxfee", ""));
return nullptr;
}
if (n > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-mintxfee").translated + " " +
_("This is the minimum transaction fee you pay on every transaction.").translated);
warnings.push_back(AmountHighWarn("-mintxfee") + Untranslated(" ") +
_("This is the minimum transaction fee you pay on every transaction."));
}
walletInstance->m_min_fee = CFeeRate(n);
}
@ -3828,12 +3829,12 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
if (gArgs.IsArgSet("-fallbackfee")) {
CAmount nFeePerK = 0;
if (!ParseMoney(gArgs.GetArg("-fallbackfee", ""), nFeePerK)) {
error = strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'").translated, gArgs.GetArg("-fallbackfee", ""));
error = strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), gArgs.GetArg("-fallbackfee", ""));
return nullptr;
}
if (nFeePerK > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-fallbackfee").translated + " " +
_("This is the transaction fee you may pay when fee estimates are not available.").translated);
warnings.push_back(AmountHighWarn("-fallbackfee") + Untranslated(" ") +
_("This is the transaction fee you may pay when fee estimates are not available."));
}
walletInstance->m_fallback_fee = CFeeRate(nFeePerK);
}
@ -3843,28 +3844,28 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
if (gArgs.IsArgSet("-discardfee")) {
CAmount nFeePerK = 0;
if (!ParseMoney(gArgs.GetArg("-discardfee", ""), nFeePerK)) {
error = strprintf(_("Invalid amount for -discardfee=<amount>: '%s'").translated, gArgs.GetArg("-discardfee", ""));
error = strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), gArgs.GetArg("-discardfee", ""));
return nullptr;
}
if (nFeePerK > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-discardfee").translated + " " +
_("This is the transaction fee you may discard if change is smaller than dust at this level").translated);
warnings.push_back(AmountHighWarn("-discardfee") + Untranslated(" ") +
_("This is the transaction fee you may discard if change is smaller than dust at this level"));
}
walletInstance->m_discard_rate = CFeeRate(nFeePerK);
}
if (gArgs.IsArgSet("-paytxfee")) {
CAmount nFeePerK = 0;
if (!ParseMoney(gArgs.GetArg("-paytxfee", ""), nFeePerK)) {
error = AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", "")).translated;
error = AmountErrMsg("paytxfee", gArgs.GetArg("-paytxfee", ""));
return nullptr;
}
if (nFeePerK > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-paytxfee").translated + " " +
_("This is the transaction fee you will pay if you send a transaction.").translated);
warnings.push_back(AmountHighWarn("-paytxfee") + Untranslated(" ") +
_("This is the transaction fee you will pay if you send a transaction."));
}
walletInstance->m_pay_tx_fee = CFeeRate(nFeePerK, 1000);
if (walletInstance->m_pay_tx_fee < chain.relayMinFee()) {
error = strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)").translated,
error = strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
gArgs.GetArg("-paytxfee", ""), chain.relayMinFee().ToString());
return nullptr;
}
@ -3873,23 +3874,23 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
if (gArgs.IsArgSet("-maxtxfee")) {
CAmount nMaxFee = 0;
if (!ParseMoney(gArgs.GetArg("-maxtxfee", ""), nMaxFee)) {
error = AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", "")).translated;
error = AmountErrMsg("maxtxfee", gArgs.GetArg("-maxtxfee", ""));
return nullptr;
}
if (nMaxFee > HIGH_MAX_TX_FEE) {
warnings.push_back(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction.").translated);
warnings.push_back(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
}
if (CFeeRate(nMaxFee, 1000) < chain.relayMinFee()) {
error = strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)").translated,
gArgs.GetArg("-maxtxfee", ""), chain.relayMinFee().ToString());
error = strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
gArgs.GetArg("-maxtxfee", ""), chain.relayMinFee().ToString());
return nullptr;
}
walletInstance->m_default_max_tx_fee = nMaxFee;
}
if (chain.relayMinFee().GetFeePerK() > HIGH_TX_FEE_PER_KB) {
warnings.push_back(AmountHighWarn("-minrelaytxfee").translated + " " +
_("The wallet will avoid paying less than the minimum relay fee.").translated);
warnings.push_back(AmountHighWarn("-minrelaytxfee") + Untranslated(" ") +
_("The wallet will avoid paying less than the minimum relay fee."));
}
walletInstance->m_confirm_target = gArgs.GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
@ -3949,7 +3950,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
}
if (rescan_height != block_height) {
error = _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)").translated;
error = _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)");
return nullptr;
}
}
@ -3974,7 +3975,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
{
WalletRescanReserver reserver(*walletInstance);
if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(chain.getBlockHash(rescan_height), rescan_height, {} /* max height */, reserver, true /* update */).status)) {
error = _("Failed to rescan the wallet during initialization").translated;
error = _("Failed to rescan the wallet during initialization");
return nullptr;
}
}
@ -4034,7 +4035,7 @@ const CAddressBookData* CWallet::FindAddressBookEntry(const CTxDestination& dest
return &address_book_it->second;
}
bool CWallet::UpgradeWallet(int version, std::string& error, std::vector<std::string>& warnings)
bool CWallet::UpgradeWallet(int version, bilingual_str& error, std::vector<bilingual_str>& warnings)
{
int prev_version = GetVersion();
int nMaxVersion = version;
@ -4043,12 +4044,12 @@ bool CWallet::UpgradeWallet(int version, std::string& error, std::vector<std::st
WalletLogPrintf("Performing wallet upgrade to %i\n", FEATURE_LATEST);
nMaxVersion = FEATURE_LATEST;
SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
}
else
} else {
WalletLogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion);
}
if (nMaxVersion < GetVersion())
{
error = _("Cannot downgrade wallet").translated;
error = _("Cannot downgrade wallet");
return false;
}
SetMaxVersion(nMaxVersion);
@ -4058,7 +4059,7 @@ bool CWallet::UpgradeWallet(int version, std::string& error, std::vector<std::st
// Do not upgrade versions to any version between HD_SPLIT and FEATURE_PRE_SPLIT_KEYPOOL unless already supporting HD_SPLIT
int max_version = GetVersion();
if (!CanSupportFeature(FEATURE_HD_SPLIT) && max_version >= FEATURE_HD_SPLIT && max_version < FEATURE_PRE_SPLIT_KEYPOOL) {
error = _("Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.").translated;
error = _("Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use version 169900 or no version specified.");
return false;
}

View file

@ -40,6 +40,8 @@
using LoadWalletFn = std::function<void(std::unique_ptr<interfaces::Wallet> wallet)>;
struct bilingual_str;
//! Explicitly unload and delete the wallet.
//! Blocks the current thread after signaling the unload intent so that all
//! wallet clients release the wallet.
@ -52,7 +54,7 @@ bool RemoveWallet(const std::shared_ptr<CWallet>& wallet);
bool HasWallets();
std::vector<std::shared_ptr<CWallet>> GetWallets();
std::shared_ptr<CWallet> GetWallet(const std::string& name);
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::vector<std::string>& warnings);
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error, std::vector<bilingual_str>& warnings);
std::unique_ptr<interfaces::Handler> HandleLoadWallet(LoadWalletFn load_wallet);
enum class WalletCreationStatus {
@ -61,7 +63,7 @@ enum class WalletCreationStatus {
ENCRYPTION_FAILED
};
WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::vector<std::string>& warnings, std::shared_ptr<CWallet>& result);
WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings, std::shared_ptr<CWallet>& result);
//! -paytxfee default
constexpr CAmount DEFAULT_PAY_TX_FEE = 0;
@ -1124,10 +1126,10 @@ public:
bool MarkReplaced(const uint256& originalHash, const uint256& newHash);
//! Verify wallet naming and perform salvage on the wallet if required
static bool Verify(interfaces::Chain& chain, const WalletLocation& location, bool salvage_wallet, std::string& error_string, std::vector<std::string>& warnings);
static bool Verify(interfaces::Chain& chain, const WalletLocation& location, bool salvage_wallet, bilingual_str& error_string, std::vector<bilingual_str>& warnings);
/* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
static std::shared_ptr<CWallet> CreateWalletFromFile(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::vector<std::string>& warnings, uint64_t wallet_creation_flags = 0);
static std::shared_ptr<CWallet> CreateWalletFromFile(interfaces::Chain& chain, const WalletLocation& location, bilingual_str& error, std::vector<bilingual_str>& warnings, uint64_t wallet_creation_flags = 0);
/**
* Wallet post-init setup
@ -1180,7 +1182,7 @@ public:
};
/** Upgrade the wallet */
bool UpgradeWallet(int version, std::string& error, std::vector<std::string>& warnings);
bool UpgradeWallet(int version, bilingual_str& error, std::vector<bilingual_str>& warnings);
//! Returns all unique ScriptPubKeyMans in m_internal_spk_managers and m_external_spk_managers
std::set<ScriptPubKeyMan*> GetActiveScriptPubKeyMans() const;

View file

@ -913,12 +913,12 @@ bool WalletBatch::RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, C
return true;
}
bool WalletBatch::VerifyEnvironment(const fs::path& wallet_path, std::string& errorStr)
bool WalletBatch::VerifyEnvironment(const fs::path& wallet_path, bilingual_str& errorStr)
{
return BerkeleyBatch::VerifyEnvironment(wallet_path, errorStr);
}
bool WalletBatch::VerifyDatabaseFile(const fs::path& wallet_path, std::vector<std::string>& warnings, std::string& errorStr)
bool WalletBatch::VerifyDatabaseFile(const fs::path& wallet_path, std::vector<bilingual_str>& warnings, bilingual_str& errorStr)
{
return BerkeleyBatch::VerifyDatabaseFile(wallet_path, warnings, errorStr, WalletBatch::Recover);
}

View file

@ -272,9 +272,9 @@ public:
/* Function to determine if a certain KV/key-type is a key (cryptographical key) type */
static bool IsKeyType(const std::string& strType);
/* verifies the database environment */
static bool VerifyEnvironment(const fs::path& wallet_path, std::string& errorStr);
static bool VerifyEnvironment(const fs::path& wallet_path, bilingual_str& errorStr);
/* verifies the database file */
static bool VerifyDatabaseFile(const fs::path& wallet_path, std::vector<std::string>& warnings, std::string& errorStr);
static bool VerifyDatabaseFile(const fs::path& wallet_path, std::vector<bilingual_str>& warnings, bilingual_str& errorStr);
//! write the hdchain model (external chain child index counter)
bool WriteHDChain(const CHDChain& chain);

View file

@ -4,6 +4,7 @@
#include <fs.h>
#include <util/system.h>
#include <util/translation.h>
#include <wallet/wallet.h>
#include <wallet/walletutil.h>
@ -117,7 +118,7 @@ bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
tfm::format(std::cerr, "Error: no wallet file at %s\n", name);
return false;
}
std::string error;
bilingual_str error;
if (!WalletBatch::VerifyEnvironment(path, error)) {
tfm::format(std::cerr, "Error loading %s. Is wallet being used by other process?\n", name);
return false;