Skip to content

Commit a306429

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#23721: wallet, refactor: Move restorewallet() logic to the wallet section
62fa61f refactor: remove the wallet folder if the restore fails (w0xlt) abbb7ec refactor: Move restorewallet() RPC logic to the wallet section (w0xlt) 4807f73 refactor: Implement restorewallet() logic in the wallet section (w0xlt) Pull request description: Currently `restorewallet()` logic is written in the RPC layer and it can´t be reused by GUI. So it moves this to the wallet section and then, GUI can access it. This is necessary to implement the "Restore Wallet" menu item in the GUI (which is already implemented in bitcoin-core#471 ). This commit also simplifies error handling and adds a new behavior: if the restore fails, the invalid wallet folder is removed. ACKs for top commit: achow101: ACK 62fa61f shaavan: crACK 62fa61f Tree-SHA512: 7ccfbad5943f38616ba0c2dd443c97a4b5bc1f6612dbf5a9e7a0263100aba36671fae929a2e7688442667be394645f44484af137a4802f204a33c4689eb27c39
2 parents 98c362a + 62fa61f commit a306429

File tree

11 files changed

+91
-32
lines changed

11 files changed

+91
-32
lines changed

src/interfaces/wallet.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,9 @@ class WalletClient : public ChainClient
322322
//! Return default wallet directory.
323323
virtual std::string getWalletDir() = 0;
324324

325+
//! Restore backup wallet
326+
virtual std::unique_ptr<Wallet> restoreWallet(const std::string& backup_file, const std::string& wallet_name, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;
327+
325328
//! Return available wallets in wallet directory.
326329
virtual std::vector<std::string> listWalletDir() = 0;
327330

src/rpc/protocol.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ enum RPCErrorCode
8080
RPC_WALLET_NOT_FOUND = -18, //!< Invalid wallet specified
8181
RPC_WALLET_NOT_SPECIFIED = -19, //!< No wallet specified (error when there are multiple wallets loaded)
8282
RPC_WALLET_ALREADY_LOADED = -35, //!< This same wallet is already loaded
83+
RPC_WALLET_ALREADY_EXISTS = -36, //!< There is already a wallet with the same name
8384

8485
//! Backwards compatible aliases
8586
RPC_WALLET_INVALID_ACCOUNT_NAME = RPC_WALLET_INVALID_LABEL_NAME,

src/wallet/db.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ enum class DatabaseStatus {
220220
FAILED_LOAD,
221221
FAILED_VERIFY,
222222
FAILED_ENCRYPT,
223+
FAILED_INVALID_BACKUP_FILE,
223224
};
224225

225226
/** Recursively list database paths in directory. */

src/wallet/interfaces.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,12 @@ class WalletClientImpl : public WalletClient
552552
options.require_existing = true;
553553
return MakeWallet(m_context, LoadWallet(m_context, name, true /* load_on_start */, options, status, error, warnings));
554554
}
555+
std::unique_ptr<Wallet> restoreWallet(const std::string& backup_file, const std::string& wallet_name, bilingual_str& error, std::vector<bilingual_str>& warnings) override
556+
{
557+
DatabaseStatus status;
558+
559+
return MakeWallet(m_context, RestoreWallet(m_context, backup_file, wallet_name, /*load_on_start=*/true, status, error, warnings));
560+
}
555561
std::string getWalletDir() override
556562
{
557563
return fs::PathToString(GetWalletDir());

src/wallet/rpc/backup.cpp

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1879,27 +1879,17 @@ RPCHelpMan restorewallet()
18791879

18801880
auto backup_file = fs::u8path(request.params[1].get_str());
18811881

1882-
if (!fs::exists(backup_file)) {
1883-
throw JSONRPCError(RPC_INVALID_PARAMETER, "Backup file does not exist");
1884-
}
1885-
18861882
std::string wallet_name = request.params[0].get_str();
18871883

1888-
const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::u8path(wallet_name));
1889-
1890-
if (fs::exists(wallet_path)) {
1891-
throw JSONRPCError(RPC_INVALID_PARAMETER, "Wallet name already exists.");
1892-
}
1893-
1894-
if (!TryCreateDirectories(wallet_path)) {
1895-
throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Failed to create database path '%s'. Database already exists.", wallet_path.u8string()));
1896-
}
1884+
std::optional<bool> load_on_start = request.params[2].isNull() ? std::nullopt : std::optional<bool>(request.params[2].get_bool());
18971885

1898-
auto wallet_file = wallet_path / "wallet.dat";
1886+
DatabaseStatus status;
1887+
bilingual_str error;
1888+
std::vector<bilingual_str> warnings;
18991889

1900-
fs::copy_file(backup_file, wallet_file, fs::copy_option::fail_if_exists);
1890+
const std::shared_ptr<CWallet> wallet = RestoreWallet(context, fs::PathToString(backup_file), wallet_name, load_on_start, status, error, warnings);
19011891

1902-
auto [wallet, warnings] = LoadWalletHelper(context, request.params[2], wallet_name);
1892+
HandleWalletError(wallet, status, error);
19031893

19041894
UniValue obj(UniValue::VOBJ);
19051895
obj.pushKV("name", wallet->GetName());

src/wallet/rpc/util.cpp

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -122,16 +122,8 @@ std::string LabelFromValue(const UniValue& value)
122122
return label;
123123
}
124124

125-
std::tuple<std::shared_ptr<CWallet>, std::vector<bilingual_str>> LoadWalletHelper(WalletContext& context, UniValue load_on_start_param, const std::string wallet_name)
125+
void HandleWalletError(const std::shared_ptr<CWallet> wallet, DatabaseStatus& status, bilingual_str& error)
126126
{
127-
DatabaseOptions options;
128-
DatabaseStatus status;
129-
options.require_existing = true;
130-
bilingual_str error;
131-
std::vector<bilingual_str> warnings;
132-
std::optional<bool> load_on_start = load_on_start_param.isNull() ? std::nullopt : std::optional<bool>(load_on_start_param.get_bool());
133-
std::shared_ptr<CWallet> const wallet = LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings);
134-
135127
if (!wallet) {
136128
// Map bad format to not found, since bad format is returned when the
137129
// wallet directory exists, but doesn't contain a data file.
@@ -144,11 +136,15 @@ std::tuple<std::shared_ptr<CWallet>, std::vector<bilingual_str>> LoadWalletHelpe
144136
case DatabaseStatus::FAILED_ALREADY_LOADED:
145137
code = RPC_WALLET_ALREADY_LOADED;
146138
break;
139+
case DatabaseStatus::FAILED_ALREADY_EXISTS:
140+
code = RPC_WALLET_ALREADY_EXISTS;
141+
break;
142+
case DatabaseStatus::FAILED_INVALID_BACKUP_FILE:
143+
code = RPC_INVALID_PARAMETER;
144+
break;
147145
default: // RPC_WALLET_ERROR is returned for all other cases.
148146
break;
149147
}
150148
throw JSONRPCError(code, error.original);
151149
}
152-
153-
return { wallet, warnings };
154-
}
150+
}

src/wallet/rpc/util.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
struct bilingual_str;
1414
class CWallet;
15+
enum class DatabaseStatus;
1516
class JSONRPCRequest;
1617
class LegacyScriptPubKeyMan;
1718
class UniValue;
@@ -37,6 +38,6 @@ bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param);
3738
bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet);
3839
std::string LabelFromValue(const UniValue& value);
3940

40-
std::tuple<std::shared_ptr<CWallet>, std::vector<bilingual_str>> LoadWalletHelper(WalletContext& context, UniValue load_on_start_param, const std::string wallet_name);
41+
void HandleWalletError(const std::shared_ptr<CWallet> wallet, DatabaseStatus& status, bilingual_str& error);
4142

4243
#endif // BITCOIN_WALLET_RPC_UTIL_H

src/wallet/rpc/wallet.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,15 @@ static RPCHelpMan loadwallet()
215215
WalletContext& context = EnsureWalletContext(request.context);
216216
const std::string name(request.params[0].get_str());
217217

218-
auto [wallet, warnings] = LoadWalletHelper(context, request.params[1], name);
218+
DatabaseOptions options;
219+
DatabaseStatus status;
220+
options.require_existing = true;
221+
bilingual_str error;
222+
std::vector<bilingual_str> warnings;
223+
std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool());
224+
std::shared_ptr<CWallet> const wallet = LoadWallet(context, name, load_on_start, options, status, error, warnings);
225+
226+
HandleWalletError(wallet, status, error);
219227

220228
UniValue obj(UniValue::VOBJ);
221229
obj.pushKV("name", wallet->GetName());

src/wallet/wallet.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,38 @@ std::shared_ptr<CWallet> CreateWallet(WalletContext& context, const std::string&
357357
return wallet;
358358
}
359359

360+
std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const std::string& backup_file, const std::string& wallet_name, std::optional<bool> load_on_start, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
361+
{
362+
DatabaseOptions options;
363+
options.require_existing = true;
364+
365+
if (!fs::exists(fs::u8path(backup_file))) {
366+
error = Untranslated("Backup file does not exist");
367+
status = DatabaseStatus::FAILED_INVALID_BACKUP_FILE;
368+
return nullptr;
369+
}
370+
371+
const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::u8path(wallet_name));
372+
373+
if (fs::exists(wallet_path) || !TryCreateDirectories(wallet_path)) {
374+
error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", fs::PathToString(wallet_path)));
375+
status = DatabaseStatus::FAILED_ALREADY_EXISTS;
376+
return nullptr;
377+
}
378+
379+
auto wallet_file = wallet_path / "wallet.dat";
380+
fs::copy_file(backup_file, wallet_file, fs::copy_option::fail_if_exists);
381+
382+
auto wallet = LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings);
383+
384+
if (!wallet) {
385+
fs::remove(wallet_file);
386+
fs::remove(wallet_path);
387+
}
388+
389+
return wallet;
390+
}
391+
360392
/** @defgroup mapWallet
361393
*
362394
* @{

src/wallet/wallet.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ std::vector<std::shared_ptr<CWallet>> GetWallets(WalletContext& context);
6060
std::shared_ptr<CWallet> GetWallet(WalletContext& context, const std::string& name);
6161
std::shared_ptr<CWallet> LoadWallet(WalletContext& context, const std::string& name, std::optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings);
6262
std::shared_ptr<CWallet> CreateWallet(WalletContext& context, const std::string& name, std::optional<bool> load_on_start, DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings);
63+
std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const std::string& backup_file, const std::string& wallet_name, std::optional<bool> load_on_start, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings);
6364
std::unique_ptr<interfaces::Handler> HandleLoadWallet(WalletContext& context, LoadWalletFn load_wallet);
6465
std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
6566

0 commit comments

Comments
 (0)