v30.3-roots.1 · Commit 24: [PATCH 24/68] feat(qt): add guarded private key sweep dialog
src/qt/walletmodel.cpp
Before: src/qt/walletmodel.cpp · After: src/qt/walletmodel.cpp
File metadata
index 694fb535b572ec192b2bb7c1db240052d2e9495e..9936f1c045d89e23583fc45e1f7f014319a360cf 100644
Download original patch · Release notes
Diff rows 1–99 of 99. Line numbers refer to the original before/after files.
+ Added− RemovedUnmarked lines are context.
Scroll the code area horizontally to read long lines. Before is on the left; after is on the right. Unified view fits narrow screens more easily.
src/qt/walletmodel.cpp
CHANGED
|
@@ -22,6 +22,8 @@
|
|
| 22 |
#include <node/types.h>
|
| 23 |
#include <psbt.h>
|
| 24 |
#include <util/translation.h>
|
|
|
|
|
|
|
| 25 |
#include <wallet/coincontrol.h>
|
| 26 |
#include <wallet/wallet.h>
|
| 27 |
|
|
@@ -51,14 +53,52 @@ WalletModel::WalletModel(std::unique_ptr<interfaces::Wallet> wallet, ClientModel
|
|
| 51 |
transactionTableModel = new TransactionTableModel(platformStyle, this);
|
| 52 |
recentRequestsTableModel = new RecentRequestsTableModel(this);
|
| 53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
subscribeToCoreSignals();
|
| 55 |
}
|
| 56 |
|
| 57 |
WalletModel::~WalletModel()
|
| 58 |
{
|
|
|
|
|
|
|
|
|
|
| 59 |
unsubscribeFromCoreSignals();
|
| 60 |
}
|
| 61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
void WalletModel::startPollBalance()
|
| 63 |
{
|
| 64 |
// Update the cached balance right away, so every view can make use of it,
|
|
@@ -105,6 +145,12 @@ void WalletModel::pollBalanceChanged()
|
|
| 105 |
}
|
| 106 |
|
| 107 |
if (fForceCheckBalanceChanged || block_hash != m_cached_last_update_tip) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
fForceCheckBalanceChanged = false;
|
| 109 |
|
| 110 |
// Balance and number of transactions might have changed
|
|
@@ -133,6 +179,9 @@ void WalletModel::updateTransaction()
|
|
| 133 |
{
|
| 134 |
// Balance and number of transactions might have changed
|
| 135 |
fForceCheckBalanceChanged = true;
|
|
|
|
|
|
|
|
|
|
| 136 |
}
|
| 137 |
|
| 138 |
void WalletModel::updateAddressBook(const QString &address, const QString &label,
|
|
@@ -354,7 +403,10 @@ bool WalletModel::changePassphrase(const SecureString &oldPass, const SecureStri
|
|
| 354 |
static void NotifyUnload(WalletModel* walletModel)
|
| 355 |
{
|
| 356 |
qDebug() << "NotifyUnload";
|
| 357 |
-
bool invoked = QMetaObject::invokeMethod(walletModel, "unload");
|
|
|
|
|
|
|
|
|
|
| 358 |
assert(invoked);
|
| 359 |
}
|
| 360 |
|
|
@@ -418,6 +470,7 @@ void WalletModel::subscribeToCoreSignals()
|
|
| 418 |
|
| 419 |
void WalletModel::unsubscribeFromCoreSignals()
|
| 420 |
{
|
|
|
|
| 421 |
// Disconnect signals from wallet
|
| 422 |
m_handler_unload->disconnect();
|
| 423 |
m_handler_status_changed->disconnect();
|
|
|
|
| 22 |
#include <node/types.h>
|
| 23 |
#include <psbt.h>
|
| 24 |
#include <util/translation.h>
|
| 25 |
+
#include <util/threadnames.h>
|
| 26 |
+
#include <util/rbf.h>
|
| 27 |
#include <wallet/coincontrol.h>
|
| 28 |
#include <wallet/wallet.h>
|
| 29 |
|
|
|
|
| 53 |
transactionTableModel = new TransactionTableModel(platformStyle, this);
|
| 54 |
recentRequestsTableModel = new RecentRequestsTableModel(this);
|
| 55 |
|
| 56 |
+
m_sweep_context.moveToThread(&m_sweep_thread);
|
| 57 |
+
m_sweep_thread.start();
|
| 58 |
+
QTimer::singleShot(0, &m_sweep_context, [] { util::ThreadRename("qt-sweep"); });
|
| 59 |
+
|
| 60 |
subscribeToCoreSignals();
|
| 61 |
}
|
| 62 |
|
| 63 |
WalletModel::~WalletModel()
|
| 64 |
{
|
| 65 |
+
invalidateSweepRequests();
|
| 66 |
+
m_sweep_thread.quit();
|
| 67 |
+
m_sweep_thread.wait();
|
| 68 |
unsubscribeFromCoreSignals();
|
| 69 |
}
|
| 70 |
|
| 71 |
+
uint64_t WalletModel::invalidateSweepRequests()
|
| 72 |
+
{
|
| 73 |
+
++m_sweep_request_generation;
|
| 74 |
+
Q_EMIT sweepRequestInvalidated(m_sweep_request_generation);
|
| 75 |
+
return m_sweep_request_generation;
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
uint64_t WalletModel::requestSweep(SecureString private_key, CTxDestination destination, bool broadcast,
|
| 79 |
+
std::optional<Txid> expected_txid)
|
| 80 |
+
{
|
| 81 |
+
const uint64_t generation{++m_sweep_request_generation};
|
| 82 |
+
QMetaObject::invokeMethod(&m_sweep_context, [this, generation, private_key = std::move(private_key), destination = std::move(destination), broadcast, expected_txid]() mutable {
|
| 83 |
+
auto result{m_wallet->sweepPrivateKey(private_key, destination, broadcast, expected_txid)};
|
| 84 |
+
private_key.clear();
|
| 85 |
+
|
| 86 |
+
const bool success{result.has_value()};
|
| 87 |
+
const QString error{success ? QString{} : QString::fromStdString(util::ErrorString(result).original)};
|
| 88 |
+
const qint64 amount{success ? result->amount : 0};
|
| 89 |
+
const qint64 fee{success ? result->fee : 0};
|
| 90 |
+
const quint64 inputs{success ? result->inputs : 0};
|
| 91 |
+
const qint64 vsize{success ? result->vsize : 0};
|
| 92 |
+
const bool rbf{success && result->tx && SignalsOptInRBF(*result->tx)};
|
| 93 |
+
const QString txid{success && result->tx ? QString::fromStdString(result->tx->GetHash().ToString()) : QString{}};
|
| 94 |
+
QMetaObject::invokeMethod(this, [this, generation, broadcast, success, error, amount, fee, inputs, vsize, rbf, txid] {
|
| 95 |
+
if (generation != m_sweep_request_generation) return;
|
| 96 |
+
Q_EMIT sweepFinished(generation, broadcast, success, error, amount, fee, inputs, vsize, rbf, txid);
|
| 97 |
+
}, Qt::QueuedConnection);
|
| 98 |
+
}, Qt::QueuedConnection);
|
| 99 |
+
return generation;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
void WalletModel::startPollBalance()
|
| 103 |
{
|
| 104 |
// Update the cached balance right away, so every view can make use of it,
|
|
|
|
| 145 |
}
|
| 146 |
|
| 147 |
if (fForceCheckBalanceChanged || block_hash != m_cached_last_update_tip) {
|
| 148 |
+
if (!m_cached_last_update_tip.IsNull() && block_hash != m_cached_last_update_tip) {
|
| 149 |
+
// A sweep preview commits to the currently observed chain state.
|
| 150 |
+
// Do not leave a key or a broadcastable preview around after a tip
|
| 151 |
+
// change; the dialog must collect fresh input and preview again.
|
| 152 |
+
invalidateSweepRequests();
|
| 153 |
+
}
|
| 154 |
fForceCheckBalanceChanged = false;
|
| 155 |
|
| 156 |
// Balance and number of transactions might have changed
|
|
|
|
| 179 |
{
|
| 180 |
// Balance and number of transactions might have changed
|
| 181 |
fForceCheckBalanceChanged = true;
|
| 182 |
+
// A competing spend or wallet update can invalidate a sweep before the
|
| 183 |
+
// next periodic balance refresh observes it.
|
| 184 |
+
invalidateSweepRequests();
|
| 185 |
}
|
| 186 |
|
| 187 |
void WalletModel::updateAddressBook(const QString &address, const QString &label,
|
|
|
|
| 403 |
static void NotifyUnload(WalletModel* walletModel)
|
| 404 |
{
|
| 405 |
qDebug() << "NotifyUnload";
|
| 406 |
+
bool invoked = QMetaObject::invokeMethod(walletModel, [walletModel] {
|
| 407 |
+
walletModel->invalidateSweepRequests();
|
| 408 |
+
Q_EMIT walletModel->unload();
|
| 409 |
+
});
|
| 410 |
assert(invoked);
|
| 411 |
}
|
| 412 |
|
|
|
|
| 470 |
|
| 471 |
void WalletModel::unsubscribeFromCoreSignals()
|
| 472 |
{
|
| 473 |
+
invalidateSweepRequests();
|
| 474 |
// Disconnect signals from wallet
|
| 475 |
m_handler_unload->disconnect();
|
| 476 |
m_handler_status_changed->disconnect();
|