Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/interfaces/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ namespace wallet {
class CCoinControl;
class CWallet;
enum isminetype : unsigned int;
enum class RescanStatus : uint8_t;
struct CRecipient;
struct WalletContext;
using isminefilter = std::underlying_type<isminetype>::type;
Expand Down Expand Up @@ -93,6 +94,9 @@ class Wallet
virtual bool changeWalletPassphrase(const SecureString& old_wallet_passphrase,
const SecureString& new_wallet_passphrase) = 0;

//! Initiate a rescan. Returns status indicating success, failure, abort, or already rescanning.
virtual wallet::RescanStatus startRescan(bool from_genesis) = 0;

//! Abort a rescan.
virtual void abortRescan() = 0;

Expand Down
2 changes: 2 additions & 0 deletions src/qt/bitcoingui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,8 @@ void BitcoinGUI::setWalletController(WalletController* wallet_controller)
m_wallet_controller = nullptr;
});

rpcConsole->setWalletController(wallet_controller);

auto activity = new LoadWalletsActivity(m_wallet_controller, this);
activity->load();
}
Expand Down
18 changes: 9 additions & 9 deletions src/qt/forms/debugwindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
<item>
<widget class="QPushButton" name="btnRepair">
<property name="text">
<string>&amp;Wallet Repair</string>
<string>&amp;Repair</string>
</property>
<property name="checkable">
<bool>true</bool>
Expand Down Expand Up @@ -1728,7 +1728,7 @@
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_repair_header">
<property name="text">
<string>Wallet repair options.</string>
<string>Repair options.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
Expand All @@ -1738,7 +1738,7 @@
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_repair_helptext">
<property name="text">
<string>The buttons below will restart the wallet with command-line options to repair the wallet, fix issues with corrupt blockchain files or missing/obsolete transactions.</string>
<string>The buttons below will trigger repair actions to fix issues with corrupt files or missing/obsolete transactions.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
Expand All @@ -1758,14 +1758,14 @@
</size>
</property>
<property name="text">
<string>Rescan blockchain files 1</string>
<string>Rescan Chain</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_repair_rescan1">
<property name="text">
<string>-rescan=1: Rescan the block chain for missing wallet transactions starting from wallet creation time.</string>
<string>Rescan the chain for missing wallet transactions starting from wallet creation time.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
Expand All @@ -1781,14 +1781,14 @@
</size>
</property>
<property name="text">
<string>Rescan blockchain files 2</string>
<string>Rescan Chain (full)</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_repair_rescan2">
<property name="text">
<string>-rescan=2: Rescan the block chain for missing wallet transactions starting from genesis block.</string>
<string>Rescan the chain for missing wallet transactions starting from genesis block.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
Expand All @@ -1798,14 +1798,14 @@
<item row="5" column="0">
<widget class="QPushButton" name="btn_reindex">
<property name="text">
<string>Rebuild index</string>
<string>Rebuild Index</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="label_repair_reindex">
<property name="text">
<string>-reindex: Rebuild block chain index from current blk000??.dat files.</string>
<string>Restarts the client to rebuild the chain index from current blk000??.dat files.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
Expand Down
95 changes: 63 additions & 32 deletions src/qt/rpcconsole.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <qt/clientmodel.h>
#include <qt/guiutil.h>
#include <qt/peertablesortproxy.h>
#include <qt/walletcontroller.h>
#include <qt/walletmodel.h>
#include <rpc/client.h>
#include <rpc/server.h>
Expand Down Expand Up @@ -70,8 +71,6 @@ const char fontSizeSettingsKey[] = "consoleFontSize";
const TrafficGraphData::GraphRange INITIAL_TRAFFIC_GRAPH_SETTING = TrafficGraphData::Range_30m;

// Repair parameters
const QString RESCAN1("-rescan=1");
const QString RESCAN2("-rescan=2");
const QString REINDEX("-reindex");

namespace {
Expand Down Expand Up @@ -574,12 +573,15 @@ RPCConsole::RPCConsole(interfaces::Node& node, QWidget* parent, Qt::WindowFlags
ui->WalletSelector->setVisible(false);
ui->WalletSelectorLabel->setVisible(false);

// Wallet Repair Buttons
// Repair Buttons
// Disable wallet repair options that require a wallet (enable them later when a wallet is added)
ui->btn_rescan1->setEnabled(false);
ui->btn_rescan2->setEnabled(false);
#ifdef ENABLE_WALLET
connect(ui->btn_rescan1, &QPushButton::clicked, this, &RPCConsole::walletRescan1);
connect(ui->btn_rescan2, &QPushButton::clicked, this, &RPCConsole::walletRescan2);
connect(ui->WalletSelector, qOverload<int>(&QComboBox::currentIndexChanged), this, &RPCConsole::onWalletChanged);
#endif // ENABLE_WALLET
connect(ui->btn_reindex, &QPushButton::clicked, this, &RPCConsole::walletReindex);

// Register RPC timer interface
Expand Down Expand Up @@ -820,47 +822,41 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
}

#ifdef ENABLE_WALLET
void RPCConsole::setWalletController(WalletController* wallet_controller)
{
m_wallet_controller = wallet_controller;
}

void RPCConsole::addWallet(WalletModel * const walletModel)
{
// use name for text and wallet model for internal data object (to allow to move to a wallet id later)
ui->WalletSelector->addItem(walletModel->getDisplayName(), QVariant::fromValue(walletModel));
if (ui->WalletSelector->count() == 2) {
// First wallet added, set to default to match wallet RPC behavior
ui->WalletSelector->setCurrentIndex(1);
// The only loaded wallet
ui->btn_rescan1->setEnabled(true);
ui->btn_rescan2->setEnabled(true);
QString wallet_path = GUIUtil::PathToQString(GetWalletDir()) + QDir::separator().toLatin1();
QString wallet_name = walletModel->getWalletName().isEmpty() ? "wallet.dat" : walletModel->getWalletName();
ui->wallet_path->setText(wallet_path + wallet_name);
} else {
}

// Update wallet path and button states for currently selected wallet
onWalletChanged();

// Show wallet selector when multiple wallets are loaded
if (ui->WalletSelector->count() > 2) {
ui->WalletSelector->setVisible(true);
ui->WalletSelectorLabel->setVisible(true);
// No wallet recovery for multiple loaded wallets
ui->btn_rescan1->setEnabled(false);
ui->btn_rescan2->setEnabled(false);
ui->wallet_path->clear();
}
}

void RPCConsole::removeWallet(WalletModel * const walletModel)
{
ui->WalletSelector->removeItem(ui->WalletSelector->findData(QVariant::fromValue(walletModel)));

// Update wallet path and button states for currently selected wallet (or clear/disable if none)
onWalletChanged();

// Hide wallet selector when back to single wallet
if (ui->WalletSelector->count() == 2) {
ui->WalletSelector->setVisible(false);
ui->WalletSelectorLabel->setVisible(false);
// Back to the only loaded wallet
ui->btn_rescan1->setEnabled(true);
ui->btn_rescan2->setEnabled(true);
WalletModel* wallet_model = ui->WalletSelector->itemData(1).value<WalletModel*>();
QString wallet_path = GUIUtil::PathToQString(GetWalletDir()) + QDir::separator().toLatin1();
QString wallet_name = wallet_model->getWalletName().isEmpty() ? "wallet.dat" : wallet_model->getWalletName();
ui->wallet_path->setText(wallet_path + wallet_name);
} else {
// No wallet recovery for multiple loaded wallets
ui->btn_rescan1->setEnabled(false);
ui->btn_rescan2->setEnabled(false);
ui->wallet_path->clear();
}
}

Expand All @@ -869,6 +865,24 @@ void RPCConsole::setCurrentWallet(WalletModel* const wallet_model)
QVariant data = QVariant::fromValue(wallet_model);
ui->WalletSelector->setCurrentIndex(ui->WalletSelector->findData(data));
}

void RPCConsole::onWalletChanged()
{
WalletModel* wallet_model = ui->WalletSelector->currentData().value<WalletModel*>();
if (wallet_model) {
QString wallet_path = GUIUtil::PathToQString(GetWalletDir()) + QDir::separator().toLatin1();
QString wallet_name = wallet_model->getWalletName().isEmpty() ? "wallet.dat" : wallet_model->getWalletName();
ui->wallet_path->setText(wallet_path + wallet_name);
// Enable rescan buttons when a valid wallet is selected
ui->btn_rescan1->setEnabled(true);
ui->btn_rescan2->setEnabled(true);
} else {
ui->wallet_path->clear();
// Disable rescan buttons when no wallet is selected (e.g., "(none)")
ui->btn_rescan1->setEnabled(false);
ui->btn_rescan2->setEnabled(false);
}
}
#endif

static QString categoryClass(int category)
Expand Down Expand Up @@ -917,17 +931,36 @@ void RPCConsole::setFontSize(int newSize)
ui->messagesWidget->verticalScrollBar()->setValue(oldPosFactor * ui->messagesWidget->verticalScrollBar()->maximum());
}

/** Restart wallet with "-rescan=1" */
#ifdef ENABLE_WALLET
void RPCConsole::walletRescan(bool from_genesis)
{
if (!m_wallet_controller) {
QMessageBox::critical(this, PACKAGE_NAME, QObject::tr("Error: Wallet controller not available."));
return;
}

WalletModel* wallet_model{ui->WalletSelector->currentData().value<WalletModel*>()};
if (!wallet_model) {
QMessageBox::critical(this, PACKAGE_NAME, QObject::tr("Error: Rescan failed. Wallet not loaded."));
return;
}

auto activity = new RescanWalletActivity(m_wallet_controller, this);
activity->rescan(wallet_model, from_genesis);
}

/** Rescan wallet from wallet creation */
void RPCConsole::walletRescan1()
{
buildParameterlist(RESCAN1);
walletRescan(/*from_genesis=*/false);
}

/** Restart wallet with "-rescan=2" */
/** Rescan wallet from genesis block */
void RPCConsole::walletRescan2()
{
buildParameterlist(RESCAN2);
walletRescan(/*from_genesis=*/true);
}
#endif

/** Restart wallet with "-reindex" */
void RPCConsole::walletReindex()
Expand All @@ -952,8 +985,6 @@ void RPCConsole::buildParameterlist(QString arg)
}

// Remove existing repair-options
args.removeAll(RESCAN1);
args.removeAll(RESCAN2);
args.removeAll(REINDEX);

// Append repair parameter to command line.
Expand Down
15 changes: 13 additions & 2 deletions src/qt/rpcconsole.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
class ClientModel;
class RPCExecutor;
class RPCTimerInterface;
class WalletController;
class WalletModel;

namespace interfaces {
Expand Down Expand Up @@ -58,6 +59,7 @@ class RPCConsole: public QWidget
void setClientModel(ClientModel *model = nullptr, int bestblock_height = 0, int64_t bestblock_date = 0, uint256 bestblock_hash = uint256(), double verification_progress = 0.0);

#ifdef ENABLE_WALLET
void setWalletController(WalletController* wallet_controller);
void addWallet(WalletModel* const walletModel);
void removeWallet(WalletModel* const walletModel);
#endif // ENABLE_WALLET
Expand Down Expand Up @@ -117,10 +119,12 @@ public Q_SLOTS:
void fontSmaller();
void setFontSize(int newSize);

/** Wallet repair options */
/** Repair options */
void walletReindex();
#ifdef ENABLE_WALLET
void walletRescan1();
void walletRescan2();
void walletReindex();
#endif // ENABLE_WALLET

/** Append the message to the message widget */
void message(int category, const QString &msg) { message(category, msg, false); }
Expand Down Expand Up @@ -174,6 +178,12 @@ public Q_SLOTS:
void setButtonIcons();
/** Reload some themes related widgets */
void reloadThemedWidgets();
#ifdef ENABLE_WALLET
/** Initiate a wallet rescan */
void walletRescan(bool from_genesis);
/** Update wallet UI when selected wallet changes */
void onWalletChanged();
#endif // ENABLE_WALLET

enum ColumnWidths
{
Expand All @@ -188,6 +198,7 @@ public Q_SLOTS:
interfaces::Node& m_node;
Ui::RPCConsole* const ui;
ClientModel *clientModel = nullptr;
WalletController* m_wallet_controller{nullptr};
QButtonGroup* pageButtons = nullptr;
QStringList history;
int historyPtr = 0;
Expand Down
44 changes: 44 additions & 0 deletions src/qt/walletcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,3 +511,47 @@ void RestoreWalletActivity::finish()

Q_EMIT finished();
}

RescanWalletActivity::RescanWalletActivity(WalletController* wallet_controller, QWidget* parent_widget)
: WalletControllerActivity(wallet_controller, parent_widget)
{
}

void RescanWalletActivity::rescan(WalletModel* wallet_model, bool from_genesis)
{
m_rescan_wallet_model = wallet_model;

QTimer::singleShot(0, worker(), [this, from_genesis] {
if (m_rescan_wallet_model) {
// Emits its own progress bar
m_rescan_status = m_rescan_wallet_model->wallet().startRescan(from_genesis);
} else {
// Wallet was closed before rescan could start
m_rescan_status = wallet::RescanStatus::FAILURE;
}
QTimer::singleShot(0, this, &RescanWalletActivity::finish);
});
Comment thread
kwvg marked this conversation as resolved.
}

void RescanWalletActivity::finish()
{
switch (m_rescan_status) {
case wallet::RescanStatus::BUSY:
QMessageBox::warning(m_parent_widget, tr("Rescan unavailable"), tr("Wallet is currently rescanning. Abort existing rescan or wait."));
Q_EMIT rescanFailed();
break;
case wallet::RescanStatus::FAILURE:
QMessageBox::critical(m_parent_widget, tr("Rescan wallet failed"), tr("Rescan failed. Potentially corrupted data files."));
Q_EMIT rescanFailed();
break;
case wallet::RescanStatus::SUCCESS:
Q_EMIT rescanComplete();
break;
case wallet::RescanStatus::USER_ABORT:
QMessageBox::information(m_parent_widget, tr("Rescan aborted"), tr("Wallet rescan was aborted."));
Q_EMIT rescanFailed();
break;
}

Q_EMIT finished();
}
Loading
Loading