Skip to content

Commit 000abbb

Browse files
committed
Merge #13111: Add unloadwallet RPC
fe65bde bugfix: Delete walletView in WalletFrame::removeWallet (João Barbosa) 0b82bac bugfix: Remove dangling wallet env instance (João Barbosa) 0ee77b2 ui: Support wallets unloaded dynamically (João Barbosa) 9f9b50d doc: Add release notes for unloadwallet RPC (João Barbosa) ccbf7ae test: Wallet methods are disabled when no wallet is loaded (João Barbosa) 4940a20 test: Add functional tests for unloadwallet RPC (João Barbosa) 6608c36 rpc: Add unloadwallet RPC (João Barbosa) 537efe1 rpc: Extract GetWalletNameFromJSONRPCRequest from GetWalletForJSONRPCRequest (João Barbosa) Pull request description: This patch adds wallet unload feature via RPC. It also adds UI support for unloaded wallets. Tree-SHA512: 7c7f9f32f7a2266d2df574aa6b95f993c3dc82736f93304562122beb8756fb28cd22d03866b48f493c747441f22d30e196b098dec435cc25e035633f090351ea
2 parents 6579d80 + fe65bde commit 000abbb

16 files changed

+194
-22
lines changed

doc/release-notes-pr10740.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
Dynamic loading and creation of wallets
22
---------------------------------------
33

4-
Previously, wallets could only be loaded or created at startup, by specifying `-wallet` parameters on the command line or in the bitcoin.conf file. It is now possible to load and create wallets dynamically at runtime:
4+
Previously, wallets could only be loaded or created at startup, by specifying `-wallet` parameters on the command line or in the bitcoin.conf file. It is now possible to load, create and unload wallets dynamically at runtime:
55

66
- Existing wallets can be loaded by calling the `loadwallet` RPC. The wallet can be specified as file/directory basename (which must be located in the `walletdir` directory), or as an absolute path to a file/directory.
77
- New wallets can be created (and loaded) by calling the `createwallet` RPC. The provided name must not match a wallet file in the `walletdir` directory or the name of a wallet that is currently loaded.
8+
- Loaded wallets can be unloaded by calling the `unloadwallet` RPC.
89

910
This feature is currently only available through the RPC interface.

src/interfaces/wallet.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,10 @@ class WalletImpl : public Wallet
429429
bool hdEnabled() override { return m_wallet.IsHDEnabled(); }
430430
OutputType getDefaultAddressType() override { return m_wallet.m_default_address_type; }
431431
OutputType getDefaultChangeType() override { return m_wallet.m_default_change_type; }
432+
std::unique_ptr<Handler> handleUnload(UnloadFn fn) override
433+
{
434+
return MakeHandler(m_wallet.NotifyUnload.connect(fn));
435+
}
432436
std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override
433437
{
434438
return MakeHandler(m_wallet.ShowProgress.connect(fn));

src/interfaces/wallet.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,10 @@ class Wallet
242242
// Get default change type.
243243
virtual OutputType getDefaultChangeType() = 0;
244244

245+
//! Register handler for unload message.
246+
using UnloadFn = std::function<void()>;
247+
virtual std::unique_ptr<Handler> handleUnload(UnloadFn fn) = 0;
248+
245249
//! Register handler for show progress messages.
246250
using ShowProgressFn = std::function<void(const std::string& title, int progress)>;
247251
virtual std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) = 0;

src/qt/bitcoin.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ public Q_SLOTS:
238238
/// Handle runaway exceptions. Shows a message box with the problem and quits the program.
239239
void handleRunawayException(const QString &message);
240240
void addWallet(WalletModel* walletModel);
241+
void removeWallet();
241242

242243
Q_SIGNALS:
243244
void requestedInitialize();
@@ -467,11 +468,22 @@ void BitcoinApplication::addWallet(WalletModel* walletModel)
467468

468469
connect(walletModel, SIGNAL(coinsSent(WalletModel*, SendCoinsRecipient, QByteArray)),
469470
paymentServer, SLOT(fetchPaymentACK(WalletModel*, const SendCoinsRecipient&, QByteArray)));
471+
connect(walletModel, SIGNAL(unload()), this, SLOT(removeWallet()));
470472

471473
m_wallet_models.push_back(walletModel);
472474
#endif
473475
}
474476

477+
void BitcoinApplication::removeWallet()
478+
{
479+
#ifdef ENABLE_WALLET
480+
WalletModel* walletModel = static_cast<WalletModel*>(sender());
481+
m_wallet_models.erase(std::find(m_wallet_models.begin(), m_wallet_models.end(), walletModel));
482+
window->removeWallet(walletModel);
483+
walletModel->deleteLater();
484+
#endif
485+
}
486+
475487
void BitcoinApplication::initializeResult(bool success)
476488
{
477489
qDebug() << __func__ << ": Initialization result: " << success;
@@ -491,8 +503,10 @@ void BitcoinApplication::initializeResult(bool success)
491503

492504
#ifdef ENABLE_WALLET
493505
m_handler_load_wallet = m_node.handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) {
494-
QMetaObject::invokeMethod(this, "addWallet", Qt::QueuedConnection,
495-
Q_ARG(WalletModel*, new WalletModel(std::move(wallet), m_node, platformStyle, optionsModel)));
506+
WalletModel* wallet_model = new WalletModel(std::move(wallet), m_node, platformStyle, optionsModel, nullptr);
507+
// Fix wallet model thread affinity.
508+
wallet_model->moveToThread(thread());
509+
QMetaObject::invokeMethod(this, "addWallet", Qt::QueuedConnection, Q_ARG(WalletModel*, wallet_model));
496510
});
497511

498512
for (auto& wallet : m_node.getWallets()) {

src/qt/bitcoingui.cpp

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty
120120
modalOverlay(0),
121121
prevBlocks(0),
122122
spinnerFrame(0),
123+
m_wallet_selector_label(nullptr),
123124
platformStyle(_platformStyle)
124125
{
125126
QSettings settings;
@@ -477,6 +478,16 @@ void BitcoinGUI::createToolBars()
477478

478479
m_wallet_selector = new QComboBox();
479480
connect(m_wallet_selector, SIGNAL(currentIndexChanged(int)), this, SLOT(setCurrentWalletBySelectorIndex(int)));
481+
482+
m_wallet_selector_label = new QLabel();
483+
m_wallet_selector_label->setText(tr("Wallet:") + " ");
484+
m_wallet_selector_label->setBuddy(m_wallet_selector);
485+
486+
m_wallet_selector_label_action = appToolBar->addWidget(m_wallet_selector_label);
487+
m_wallet_selector_action = appToolBar->addWidget(m_wallet_selector);
488+
489+
m_wallet_selector_label_action->setVisible(false);
490+
m_wallet_selector_action->setVisible(false);
480491
#endif
481492
}
482493
}
@@ -556,16 +567,29 @@ bool BitcoinGUI::addWallet(WalletModel *walletModel)
556567
setWalletActionsEnabled(true);
557568
m_wallet_selector->addItem(display_name, name);
558569
if (m_wallet_selector->count() == 2) {
559-
m_wallet_selector_label = new QLabel();
560-
m_wallet_selector_label->setText(tr("Wallet:") + " ");
561-
m_wallet_selector_label->setBuddy(m_wallet_selector);
562-
appToolBar->addWidget(m_wallet_selector_label);
563-
appToolBar->addWidget(m_wallet_selector);
570+
m_wallet_selector_label_action->setVisible(true);
571+
m_wallet_selector_action->setVisible(true);
564572
}
565573
rpcConsole->addWallet(walletModel);
566574
return walletFrame->addWallet(walletModel);
567575
}
568576

577+
bool BitcoinGUI::removeWallet(WalletModel* walletModel)
578+
{
579+
if (!walletFrame) return false;
580+
QString name = walletModel->getWalletName();
581+
int index = m_wallet_selector->findData(name);
582+
m_wallet_selector->removeItem(index);
583+
if (m_wallet_selector->count() == 0) {
584+
setWalletActionsEnabled(false);
585+
} else if (m_wallet_selector->count() == 1) {
586+
m_wallet_selector_label_action->setVisible(false);
587+
m_wallet_selector_action->setVisible(false);
588+
}
589+
rpcConsole->removeWallet(walletModel);
590+
return walletFrame->removeWallet(name);
591+
}
592+
569593
bool BitcoinGUI::setCurrentWallet(const QString& name)
570594
{
571595
if(!walletFrame)

src/qt/bitcoingui.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class BitcoinGUI : public QMainWindow
7070
functionality.
7171
*/
7272
bool addWallet(WalletModel *walletModel);
73+
bool removeWallet(WalletModel* walletModel);
7374
void removeAllWallets();
7475
#endif // ENABLE_WALLET
7576
bool enableWallet;
@@ -122,8 +123,10 @@ class BitcoinGUI : public QMainWindow
122123
QAction *openRPCConsoleAction;
123124
QAction *openAction;
124125
QAction *showHelpMessageAction;
126+
QAction *m_wallet_selector_label_action = nullptr;
127+
QAction *m_wallet_selector_action = nullptr;
125128

126-
QLabel *m_wallet_selector_label;
129+
QLabel *m_wallet_selector_label = nullptr;
127130
QComboBox *m_wallet_selector;
128131

129132
QSystemTrayIcon *trayIcon;

src/qt/rpcconsole.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,16 @@ void RPCConsole::addWallet(WalletModel * const walletModel)
713713
ui->WalletSelectorLabel->setVisible(true);
714714
}
715715
}
716+
717+
void RPCConsole::removeWallet(WalletModel * const walletModel)
718+
{
719+
const QString name = walletModel->getWalletName();
720+
ui->WalletSelector->removeItem(ui->WalletSelector->findData(name));
721+
if (ui->WalletSelector->count() == 2) {
722+
ui->WalletSelector->setVisible(false);
723+
ui->WalletSelectorLabel->setVisible(false);
724+
}
725+
}
716726
#endif
717727

718728
static QString categoryClass(int category)

src/qt/rpcconsole.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class RPCConsole: public QWidget
4848

4949
void setClientModel(ClientModel *model);
5050
void addWallet(WalletModel * const walletModel);
51+
void removeWallet(WalletModel* const walletModel);
5152

5253
enum MessageClass {
5354
MC_ERROR,

src/qt/walletframe.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ bool WalletFrame::removeWallet(const QString &name)
9494

9595
WalletView *walletView = mapWalletViews.take(name);
9696
walletStack->removeWidget(walletView);
97+
delete walletView;
9798
return true;
9899
}
99100

src/qt/walletmodel.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,12 @@ bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureStri
364364
}
365365

366366
// Handlers for core signals
367+
static void NotifyUnload(WalletModel* walletModel)
368+
{
369+
qDebug() << "NotifyUnload";
370+
QMetaObject::invokeMethod(walletModel, "unload", Qt::QueuedConnection);
371+
}
372+
367373
static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel)
368374
{
369375
qDebug() << "NotifyKeyStoreStatusChanged";
@@ -411,6 +417,7 @@ static void NotifyWatchonlyChanged(WalletModel *walletmodel, bool fHaveWatchonly
411417
void WalletModel::subscribeToCoreSignals()
412418
{
413419
// Connect signals to wallet
420+
m_handler_unload = m_wallet->handleUnload(boost::bind(&NotifyUnload, this));
414421
m_handler_status_changed = m_wallet->handleStatusChanged(boost::bind(&NotifyKeyStoreStatusChanged, this));
415422
m_handler_address_book_changed = m_wallet->handleAddressBookChanged(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5));
416423
m_handler_transaction_changed = m_wallet->handleTransactionChanged(boost::bind(NotifyTransactionChanged, this, _1, _2));
@@ -421,6 +428,7 @@ void WalletModel::subscribeToCoreSignals()
421428
void WalletModel::unsubscribeFromCoreSignals()
422429
{
423430
// Disconnect signals from wallet
431+
m_handler_unload->disconnect();
424432
m_handler_status_changed->disconnect();
425433
m_handler_address_book_changed->disconnect();
426434
m_handler_transaction_changed->disconnect();

0 commit comments

Comments
 (0)