v29.4-roots.4 · Commit 16: [PATCH 16/37] feat(qt): add per-send RBF override
src/qt/test/wallettests.cpp
Before: src/qt/test/wallettests.cpp · After: src/qt/test/wallettests.cpp
File metadata
index 816d47fed46042d325ba09004ed5e91f7ca7b88c..8e7031719c052206667b9ea99d45f6485f9094cd 100644
Download original patch · Release notes
Diff rows 1–110 of 110. 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/test/wallettests.cpp
CHANGED
|
@@ -26,6 +26,7 @@
|
|
| 26 |
#include <qt/walletmodel.h>
|
| 27 |
#include <script/solver.h>
|
| 28 |
#include <test/util/setup_common.h>
|
|
|
|
| 29 |
#include <validation.h>
|
| 30 |
#include <wallet/test/util.h>
|
| 31 |
#include <wallet/wallet.h>
|
|
@@ -76,7 +77,7 @@ void ConfirmSend(QString* text = nullptr, QMessageBox::StandardButton confirm_ty
|
|
| 76 |
|
| 77 |
//! Send coins to address and return txid.
|
| 78 |
uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDestination& address, CAmount amount, bool rbf,
|
| 79 |
-
QMessageBox::StandardButton confirm_type = QMessageBox::Yes)
|
| 80 |
{
|
| 81 |
QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries");
|
| 82 |
SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget());
|
|
@@ -90,7 +91,7 @@ uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDe
|
|
| 90 |
boost::signals2::scoped_connection c(wallet.NotifyTransactionChanged.connect([&txid](const uint256& hash, ChangeType status) {
|
| 91 |
if (status == CT_NEW) txid = hash;
|
| 92 |
}));
|
| 93 |
-
ConfirmSend(/*text=*/nullptr, confirm_type);
|
| 94 |
bool invoked = QMetaObject::invokeMethod(&sendCoinsDialog, "sendButtonClicked", Q_ARG(bool, false));
|
| 95 |
assert(invoked);
|
| 96 |
return txid;
|
|
@@ -273,6 +274,8 @@ public:
|
|
| 273 |
// QT_QPA_PLATFORM=cocoa build/bin/test_bitcoin-qt # macOS
|
| 274 |
void TestGUI(interfaces::Node& node, const std::shared_ptr<CWallet>& wallet)
|
| 275 |
{
|
|
|
|
|
|
|
| 276 |
// Create widgets for sending coins and listing transactions.
|
| 277 |
std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
|
| 278 |
MiniGUI mini_gui(node, platformStyle.get());
|
|
@@ -292,19 +295,42 @@ void TestGUI(interfaces::Node& node, const std::shared_ptr<CWallet>& wallet)
|
|
| 292 |
// Send two transactions, and verify they are added to transaction list.
|
| 293 |
TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
|
| 294 |
QCOMPARE(transactionTableModel->rowCount({}), 105);
|
| 295 |
-
uint256 txid1 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, /*rbf=*/false);
|
| 296 |
-
uint256 txid2 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 10 * COIN, /*rbf=*/true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 297 |
// Transaction table model updates on a QueuedConnection, so process events to ensure it's updated.
|
| 298 |
qApp->processEvents();
|
| 299 |
-
QCOMPARE(transactionTableModel->rowCount({}), 107);
|
| 300 |
QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
|
| 301 |
QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
|
|
|
|
| 302 |
|
| 303 |
// Call bumpfee. Test disabled, canceled, enabled, then failing cases.
|
| 304 |
BumpFee(transactionView, txid1, /*expectDisabled=*/true, /*expectError=*/"not BIP 125 replaceable", /*cancel=*/false);
|
| 305 |
BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/true);
|
| 306 |
BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/false);
|
| 307 |
BumpFee(transactionView, txid2, /*expectDisabled=*/true, /*expectError=*/"already bumped", /*cancel=*/false);
|
|
|
|
| 308 |
|
| 309 |
// Check current balance on OverviewPage
|
| 310 |
OverviewPage overviewPage(platformStyle.get());
|
|
@@ -443,6 +469,34 @@ void TestGUIWatchOnly(interfaces::Node& node, TestChain100Setup& test)
|
|
| 443 |
PartiallySignedTransaction psbt;
|
| 444 |
std::string err;
|
| 445 |
QVERIFY(DecodeRawPSBT(psbt, MakeByteSpan(*decoded_psbt), err));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 446 |
}
|
| 447 |
|
| 448 |
void TestGUI(interfaces::Node& node)
|
|
|
|
| 26 |
#include <qt/walletmodel.h>
|
| 27 |
#include <script/solver.h>
|
| 28 |
#include <test/util/setup_common.h>
|
| 29 |
+
#include <util/rbf.h>
|
| 30 |
#include <validation.h>
|
| 31 |
#include <wallet/test/util.h>
|
| 32 |
#include <wallet/wallet.h>
|
|
|
|
| 77 |
|
| 78 |
//! Send coins to address and return txid.
|
| 79 |
uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDestination& address, CAmount amount, bool rbf,
|
| 80 |
+
QMessageBox::StandardButton confirm_type = QMessageBox::Yes, QString* confirmation_text = nullptr)
|
| 81 |
{
|
| 82 |
QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries");
|
| 83 |
SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget());
|
|
|
|
| 91 |
boost::signals2::scoped_connection c(wallet.NotifyTransactionChanged.connect([&txid](const uint256& hash, ChangeType status) {
|
| 92 |
if (status == CT_NEW) txid = hash;
|
| 93 |
}));
|
| 94 |
+
ConfirmSend(confirmation_text, confirm_type);
|
| 95 |
bool invoked = QMetaObject::invokeMethod(&sendCoinsDialog, "sendButtonClicked", Q_ARG(bool, false));
|
| 96 |
assert(invoked);
|
| 97 |
return txid;
|
|
|
|
| 274 |
// QT_QPA_PLATFORM=cocoa build/bin/test_bitcoin-qt # macOS
|
| 275 |
void TestGUI(interfaces::Node& node, const std::shared_ptr<CWallet>& wallet)
|
| 276 |
{
|
| 277 |
+
wallet->m_signal_rbf = false;
|
| 278 |
+
|
| 279 |
// Create widgets for sending coins and listing transactions.
|
| 280 |
std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
|
| 281 |
MiniGUI mini_gui(node, platformStyle.get());
|
|
|
|
| 295 |
// Send two transactions, and verify they are added to transaction list.
|
| 296 |
TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
|
| 297 |
QCOMPARE(transactionTableModel->rowCount({}), 105);
|
| 298 |
+
QCheckBox* rbf_checkbox = sendCoinsDialog.findChild<QCheckBox*>("optInRBF");
|
| 299 |
+
QVERIFY(rbf_checkbox);
|
| 300 |
+
QCOMPARE(rbf_checkbox->text(), "Enable Replace-By-Fee");
|
| 301 |
+
QVERIFY(rbf_checkbox->focusPolicy() != Qt::NoFocus);
|
| 302 |
+
QVERIFY(!rbf_checkbox->isChecked());
|
| 303 |
+
|
| 304 |
+
QString no_rbf_confirmation;
|
| 305 |
+
uint256 txid1 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, /*rbf=*/false, QMessageBox::Yes, &no_rbf_confirmation);
|
| 306 |
+
QString rbf_confirmation;
|
| 307 |
+
uint256 txid2 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 10 * COIN, /*rbf=*/true, QMessageBox::Yes, &rbf_confirmation);
|
| 308 |
+
QVERIFY(!SignalsOptInRBF(*wallet->mapWallet.at(txid1).tx));
|
| 309 |
+
QVERIFY(SignalsOptInRBF(*wallet->mapWallet.at(txid2).tx));
|
| 310 |
+
QVERIFY(no_rbf_confirmation.contains("Not signalling Replace-By-Fee, BIP-125."));
|
| 311 |
+
QVERIFY(rbf_confirmation.contains("signals Replace-By-Fee (BIP-125)"));
|
| 312 |
+
|
| 313 |
+
wallet->m_signal_rbf = true;
|
| 314 |
+
SendCoinsDialog default_rbf_dialog(platformStyle.get());
|
| 315 |
+
default_rbf_dialog.setModel(&walletModel);
|
| 316 |
+
QVERIFY(default_rbf_dialog.findChild<QCheckBox*>("optInRBF")->isChecked());
|
| 317 |
+
QString default_on_override_confirmation;
|
| 318 |
+
uint256 txid3 = SendCoins(*wallet.get(), default_rbf_dialog, PKHash(), COIN, /*rbf=*/false, QMessageBox::Yes, &default_on_override_confirmation);
|
| 319 |
+
QVERIFY(!SignalsOptInRBF(*wallet->mapWallet.at(txid3).tx));
|
| 320 |
+
QVERIFY(default_on_override_confirmation.contains("Not signalling Replace-By-Fee, BIP-125."));
|
| 321 |
// Transaction table model updates on a QueuedConnection, so process events to ensure it's updated.
|
| 322 |
qApp->processEvents();
|
| 323 |
+
QCOMPARE(transactionTableModel->rowCount({}), 108);
|
| 324 |
QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
|
| 325 |
QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
|
| 326 |
+
QVERIFY(FindTx(*transactionTableModel, txid3).isValid());
|
| 327 |
|
| 328 |
// Call bumpfee. Test disabled, canceled, enabled, then failing cases.
|
| 329 |
BumpFee(transactionView, txid1, /*expectDisabled=*/true, /*expectError=*/"not BIP 125 replaceable", /*cancel=*/false);
|
| 330 |
BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/true);
|
| 331 |
BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/false);
|
| 332 |
BumpFee(transactionView, txid2, /*expectDisabled=*/true, /*expectError=*/"already bumped", /*cancel=*/false);
|
| 333 |
+
BumpFee(transactionView, txid3, /*expectDisabled=*/true, /*expectError=*/"not BIP 125 replaceable", /*cancel=*/false);
|
| 334 |
|
| 335 |
// Check current balance on OverviewPage
|
| 336 |
OverviewPage overviewPage(platformStyle.get());
|
|
|
|
| 469 |
PartiallySignedTransaction psbt;
|
| 470 |
std::string err;
|
| 471 |
QVERIFY(DecodeRawPSBT(psbt, MakeByteSpan(*decoded_psbt), err));
|
| 472 |
+
QVERIFY(!SignalsOptInRBF(CTransaction{*psbt.tx}));
|
| 473 |
+
|
| 474 |
+
SendCoinsDialog rbf_psbt_dialog(platformStyle.get());
|
| 475 |
+
rbf_psbt_dialog.setModel(&walletModel);
|
| 476 |
+
rbf_psbt_dialog.getCoinControl()->destChange = GetDestinationForKey(test.coinbaseKey.GetPubKey(), OutputType::LEGACY);
|
| 477 |
+
QTimer rbf_timer;
|
| 478 |
+
rbf_timer.setInterval(500);
|
| 479 |
+
QObject::connect(&rbf_timer, &QTimer::timeout, [&](){
|
| 480 |
+
for (QWidget* widget : QApplication::topLevelWidgets()) {
|
| 481 |
+
if (widget->inherits("QMessageBox") && widget->objectName().compare("psbt_copied_message") == 0) {
|
| 482 |
+
QMessageBox* dialog = qobject_cast<QMessageBox*>(widget);
|
| 483 |
+
QAbstractButton* button = dialog->button(QMessageBox::Discard);
|
| 484 |
+
button->setEnabled(true);
|
| 485 |
+
button->click();
|
| 486 |
+
rbf_timer.stop();
|
| 487 |
+
break;
|
| 488 |
+
}
|
| 489 |
+
}
|
| 490 |
+
});
|
| 491 |
+
rbf_timer.start(500);
|
| 492 |
+
|
| 493 |
+
SendCoins(*wallet.get(), rbf_psbt_dialog, PKHash(), 5 * COIN, /*rbf=*/true, QMessageBox::Save);
|
| 494 |
+
decoded_psbt = DecodeBase64(QApplication::clipboard()->text().toStdString());
|
| 495 |
+
QVERIFY(decoded_psbt);
|
| 496 |
+
psbt = {};
|
| 497 |
+
err.clear();
|
| 498 |
+
QVERIFY(DecodeRawPSBT(psbt, MakeByteSpan(*decoded_psbt), err));
|
| 499 |
+
QVERIFY(SignalsOptInRBF(CTransaction{*psbt.tx}));
|
| 500 |
}
|
| 501 |
|
| 502 |
void TestGUI(interfaces::Node& node)
|