mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-26 17:52:13 +01:00
Merge bitcoin/bitcoin#26005: Wallet: Fix error handling (copy_file failure in RestoreWallet, and in general via interfaces)
c3e536555aa3a7db773170671da1256a2ace2094 Bugfix: Wallet: Return util::Error rather than non-error nullptr when CreateWallet/LoadWallet/RestoreWallet fail (Luke Dashjr) 335ff98c8a64eda38a2a2334102bd253f108c253 Bugfix: Wallet: Wrap RestoreWallet content in a try block to ensure exceptions become returned errors and incomplete wallet directory is removed (Luke Dashjr) Pull request description: Bug 1: `copy_file` can throw exceptions, but `RestoreWallet` is expected to return a nullptr with a populated `errors` parameter. This is fixed by wrapping `copy_file` and `LoadWallet` (for good measure) in a `try` block, and converting any exceptions to the intended return style. Bug 2: `util::Result` turns what would have been a `false` unique_ptr into a `true` nullptr result, which leads to nullptr dereferences in at least the 3 cases of wallet creation/loading/restoring. This is fixed by keeping the pointer as a plain `std::unique_ptr` until actually returning it (ie, after the nullptr check). Fixes https://github.com/bitcoin-core/gui/issues/661 ACKs for top commit: achow101: ACK c3e536555aa3a7db773170671da1256a2ace2094 Tree-SHA512: 4291b3dbbb147acea2e63a704324c9371bc16ecb4237f8753729b0b0a6e55c9758ad61bfe8bd432fd7b0bae95d8b63a9831e61ac8b8d5c0197b550a2e0f4a105
This commit is contained in:
commit
9f650062fc
@ -560,8 +560,12 @@ public:
|
||||
options.create_flags = wallet_creation_flags;
|
||||
options.create_passphrase = passphrase;
|
||||
bilingual_str error;
|
||||
util::Result<std::unique_ptr<Wallet>> wallet{MakeWallet(m_context, CreateWallet(m_context, name, /*load_on_start=*/true, options, status, error, warnings))};
|
||||
return wallet ? std::move(wallet) : util::Error{error};
|
||||
std::unique_ptr<Wallet> wallet{MakeWallet(m_context, CreateWallet(m_context, name, /*load_on_start=*/true, options, status, error, warnings))};
|
||||
if (wallet) {
|
||||
return {std::move(wallet)};
|
||||
} else {
|
||||
return util::Error{error};
|
||||
}
|
||||
}
|
||||
util::Result<std::unique_ptr<Wallet>> loadWallet(const std::string& name, std::vector<bilingual_str>& warnings) override
|
||||
{
|
||||
@ -570,15 +574,23 @@ public:
|
||||
ReadDatabaseArgs(*m_context.args, options);
|
||||
options.require_existing = true;
|
||||
bilingual_str error;
|
||||
util::Result<std::unique_ptr<Wallet>> wallet{MakeWallet(m_context, LoadWallet(m_context, name, /*load_on_start=*/true, options, status, error, warnings))};
|
||||
return wallet ? std::move(wallet) : util::Error{error};
|
||||
std::unique_ptr<Wallet> wallet{MakeWallet(m_context, LoadWallet(m_context, name, /*load_on_start=*/true, options, status, error, warnings))};
|
||||
if (wallet) {
|
||||
return {std::move(wallet)};
|
||||
} else {
|
||||
return util::Error{error};
|
||||
}
|
||||
}
|
||||
util::Result<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) override
|
||||
{
|
||||
DatabaseStatus status;
|
||||
bilingual_str error;
|
||||
util::Result<std::unique_ptr<Wallet>> wallet{MakeWallet(m_context, RestoreWallet(m_context, backup_file, wallet_name, /*load_on_start=*/true, status, error, warnings))};
|
||||
return wallet ? std::move(wallet) : util::Error{error};
|
||||
std::unique_ptr<Wallet> wallet{MakeWallet(m_context, RestoreWallet(m_context, backup_file, wallet_name, /*load_on_start=*/true, status, error, warnings))};
|
||||
if (wallet) {
|
||||
return {std::move(wallet)};
|
||||
} else {
|
||||
return util::Error{error};
|
||||
}
|
||||
}
|
||||
std::string getWalletDir() override
|
||||
{
|
||||
|
@ -386,25 +386,31 @@ std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const fs::path& b
|
||||
ReadDatabaseArgs(*context.args, options);
|
||||
options.require_existing = true;
|
||||
|
||||
if (!fs::exists(backup_file)) {
|
||||
error = Untranslated("Backup file does not exist");
|
||||
status = DatabaseStatus::FAILED_INVALID_BACKUP_FILE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::u8path(wallet_name));
|
||||
|
||||
if (fs::exists(wallet_path) || !TryCreateDirectories(wallet_path)) {
|
||||
error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", fs::PathToString(wallet_path)));
|
||||
status = DatabaseStatus::FAILED_ALREADY_EXISTS;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto wallet_file = wallet_path / "wallet.dat";
|
||||
fs::copy_file(backup_file, wallet_file, fs::copy_options::none);
|
||||
std::shared_ptr<CWallet> wallet;
|
||||
|
||||
auto wallet = LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings);
|
||||
try {
|
||||
if (!fs::exists(backup_file)) {
|
||||
error = Untranslated("Backup file does not exist");
|
||||
status = DatabaseStatus::FAILED_INVALID_BACKUP_FILE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (fs::exists(wallet_path) || !TryCreateDirectories(wallet_path)) {
|
||||
error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", fs::PathToString(wallet_path)));
|
||||
status = DatabaseStatus::FAILED_ALREADY_EXISTS;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fs::copy_file(backup_file, wallet_file, fs::copy_options::none);
|
||||
|
||||
wallet = LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings);
|
||||
} catch (const std::exception& e) {
|
||||
assert(!wallet);
|
||||
if (!error.empty()) error += Untranslated("\n");
|
||||
error += strprintf(Untranslated("Unexpected exception: %s"), e.what());
|
||||
}
|
||||
if (!wallet) {
|
||||
fs::remove(wallet_file);
|
||||
fs::remove(wallet_path);
|
||||
|
Loading…
x
Reference in New Issue
Block a user