Skip to content

Commit 32b6e3e

Browse files
w0xltshaavan
andcommitted
gui: Add Wallet Restore in the GUI
Co-authored-by: Shashwat Vangani <[email protected]>
1 parent 6d83b02 commit 32b6e3e

File tree

8 files changed

+103
-0
lines changed

8 files changed

+103
-0
lines changed

src/interfaces/wallet.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ class WalletClient : public ChainClient
318318
//! Load existing wallet.
319319
virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) = 0;
320320

321+
//! Restore backup wallet
322+
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;
323+
321324
//! Return default wallet directory.
322325
virtual std::string getWalletDir() = 0;
323326

src/qt/bitcoingui.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include <QCursor>
4747
#include <QDateTime>
4848
#include <QDragEnterEvent>
49+
#include <QInputDialog>
4950
#include <QListWidget>
5051
#include <QMenu>
5152
#include <QMenuBar>
@@ -360,6 +361,10 @@ void BitcoinGUI::createActions()
360361
m_create_wallet_action->setEnabled(false);
361362
m_create_wallet_action->setStatusTip(tr("Create a new wallet"));
362363

364+
m_restore_wallet_action = new QAction(tr("Restore Wallet…"), this);
365+
m_restore_wallet_action->setEnabled(false);
366+
m_restore_wallet_action->setStatusTip(tr("Restore a wallet from a backup file"));
367+
363368
m_close_all_wallets_action = new QAction(tr("Close All Wallets…"), this);
364369
m_close_all_wallets_action->setStatusTip(tr("Close all wallets"));
365370

@@ -433,6 +438,20 @@ void BitcoinGUI::createActions()
433438
connect(activity, &CreateWalletActivity::created, this, &BitcoinGUI::setCurrentWallet);
434439
activity->create();
435440
});
441+
connect(m_restore_wallet_action, &QAction::triggered, [this] {
442+
QString backupFile = GUIUtil::getOpenFileName(this,
443+
tr("Load Wallet Backup"), QString(),
444+
tr("Wallet Data File (*.dat)"), nullptr);
445+
if (backupFile.isEmpty()) return;
446+
447+
bool walletNameOk;
448+
QString walletName = QInputDialog::getText(this, tr("Restore Name"), tr("Wallet Name:"), QLineEdit::Normal, "", &walletNameOk);
449+
if (!walletNameOk || walletName.isEmpty()) return;
450+
451+
auto activity = new RestoreWalletActivity(m_wallet_controller, this);
452+
connect(activity, &RestoreWalletActivity::restored, this, &BitcoinGUI::setCurrentWallet);
453+
activity->restore(backupFile.toStdString(), walletName.toStdString());
454+
});
436455
connect(m_close_all_wallets_action, &QAction::triggered, [this] {
437456
m_wallet_controller->closeAllWallets(this);
438457
});
@@ -460,6 +479,7 @@ void BitcoinGUI::createMenuBar()
460479
{
461480
file->addAction(m_create_wallet_action);
462481
file->addAction(m_open_wallet_action);
482+
file->addAction(m_restore_wallet_action);
463483
file->addAction(m_close_wallet_action);
464484
file->addAction(m_close_all_wallets_action);
465485
file->addSeparator();
@@ -657,6 +677,7 @@ void BitcoinGUI::setWalletController(WalletController* wallet_controller)
657677
m_create_wallet_action->setEnabled(true);
658678
m_open_wallet_action->setEnabled(true);
659679
m_open_wallet_action->setMenu(m_open_wallet_menu);
680+
m_restore_wallet_action->setEnabled(true);
660681

661682
GUIUtil::ExceptionSafeConnect(wallet_controller, &WalletController::walletAdded, this, &BitcoinGUI::addWallet);
662683
connect(wallet_controller, &WalletController::walletRemoved, this, &BitcoinGUI::removeWallet);

src/qt/bitcoingui.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ class BitcoinGUI : public QMainWindow
158158
QAction* showHelpMessageAction = nullptr;
159159
QAction* m_create_wallet_action{nullptr};
160160
QAction* m_open_wallet_action{nullptr};
161+
QAction* m_restore_wallet_action{nullptr};
161162
QMenu* m_open_wallet_menu{nullptr};
162163
QAction* m_close_wallet_action{nullptr};
163164
QAction* m_close_all_wallets_action{nullptr};

src/qt/walletcontroller.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,3 +366,40 @@ void LoadWalletsActivity::load()
366366
QTimer::singleShot(0, this, [this] { Q_EMIT finished(); });
367367
});
368368
}
369+
370+
RestoreWalletActivity::RestoreWalletActivity(WalletController* wallet_controller, QWidget* parent_widget)
371+
: WalletControllerActivity(wallet_controller, parent_widget)
372+
{
373+
}
374+
375+
void RestoreWalletActivity::restore(const std::string& backup_file, const std::string& wallet_name)
376+
{
377+
QString name = QString::fromStdString(wallet_name);
378+
379+
showProgressDialog(
380+
tr("Restore Wallet"),
381+
tr("Restoring Wallet <b>%1</b>…").arg(name.toHtmlEscaped())
382+
);
383+
384+
QTimer::singleShot(0, worker(), [this, backup_file, wallet_name] {
385+
std::unique_ptr<interfaces::Wallet> wallet = node().walletClient().restoreWallet(backup_file, wallet_name, m_error_message, m_warning_message);
386+
387+
if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet));
388+
389+
QTimer::singleShot(0, this, &RestoreWalletActivity::finish);
390+
});
391+
}
392+
393+
void RestoreWalletActivity::finish()
394+
{
395+
if (!m_error_message.empty()) {
396+
QMessageBox::critical(m_parent_widget, tr("Restore wallet failed"), QString::fromStdString(m_error_message.translated));
397+
} else if (!m_warning_message.empty()) {
398+
QMessageBox::warning(m_parent_widget, tr("Restore wallet warning"), QString::fromStdString(Join(m_warning_message, Untranslated("\n")).translated));
399+
}
400+
401+
if (m_wallet_model) Q_EMIT restored(m_wallet_model);
402+
403+
Q_EMIT finished();
404+
}
405+

src/qt/walletcontroller.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,20 @@ class LoadWalletsActivity : public WalletControllerActivity
155155
void load();
156156
};
157157

158+
class RestoreWalletActivity : public WalletControllerActivity
159+
{
160+
Q_OBJECT
161+
162+
public:
163+
RestoreWalletActivity(WalletController* wallet_controller, QWidget* parent_widget);
164+
165+
void restore(const std::string& backup_file, const std::string& wallet_name);
166+
167+
Q_SIGNALS:
168+
void restored(WalletModel* wallet_model);
169+
170+
private:
171+
void finish();
172+
};
173+
158174
#endif // BITCOIN_QT_WALLETCONTROLLER_H

src/wallet/interfaces.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,14 @@ class WalletClientImpl : public WalletClient
549549
options.require_existing = true;
550550
return MakeWallet(m_context, LoadWallet(m_context, name, true /* load_on_start */, options, status, error, warnings));
551551
}
552+
std::unique_ptr<Wallet> restoreWallet(const std::string& backup_file, const std::string& wallet_name, bilingual_str& error, std::vector<bilingual_str>& warnings) override
553+
{
554+
DatabaseOptions options;
555+
DatabaseStatus status;
556+
options.require_existing = true;
557+
558+
return MakeWallet(m_context, RestoreWallet(m_context, backup_file, wallet_name, /* load_on_start= */ true, options, status, error, warnings));
559+
}
552560
std::string getWalletDir() override
553561
{
554562
return fs::PathToString(GetWalletDir());

src/wallet/wallet.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,22 @@ std::shared_ptr<CWallet> CreateWallet(WalletContext& context, const std::string&
353353
return wallet;
354354
}
355355

356+
std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const std::string& backup_file, const std::string& wallet_name, std::optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
357+
{
358+
const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::u8path(wallet_name));
359+
360+
if (fs::exists(wallet_path) || !TryCreateDirectories(wallet_path)) {
361+
error = Untranslated(strprintf("Failed to create database path '%s'. Database already exists.", fs::PathToString(wallet_path)));
362+
status = DatabaseStatus::FAILED_ALREADY_EXISTS;
363+
return nullptr;
364+
}
365+
366+
auto wallet_file = wallet_path / "wallet.dat";
367+
fs::copy_file(backup_file, wallet_file, fs::copy_option::fail_if_exists);
368+
369+
return LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings);
370+
}
371+
356372
/** @defgroup mapWallet
357373
*
358374
* @{

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, const DatabaseOptions& options, 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)