Skip to content
Bitcoin Roots

v30.3-roots.1 · Commit 16: [PATCH 16/68] 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 5e65dcca318d978d10c58605669197dee236daaa..a477110f9ae62f0d0b236850d143289323e9ba75 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. The two line-number columns refer to before and after.

src/qt/test/wallettests.cpp CHANGED
@@ -26,6 +26,7 @@
26
26
  #include <qt/walletmodel.h>
27
27
  #include <script/solver.h>
28
28
  #include <test/util/setup_common.h>
29
+ #include <util/rbf.h>
29
30
  #include <validation.h>
30
31
  #include <wallet/test/util.h>
31
32
  #include <wallet/wallet.h>
@@ -76,7 +77,7 @@ void ConfirmSend(QString* text = nullptr, QMessageBox::StandardButton confirm_ty
76
77
 
77
78
  //! Send coins to address and return txid.
78
79
  Txid SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDestination& address, CAmount amount, bool rbf,
79
- QMessageBox::StandardButton confirm_type = QMessageBox::Yes)
80
+ QMessageBox::StandardButton confirm_type = QMessageBox::Yes, QString* confirmation_text = nullptr)
80
81
  {
81
82
  QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries");
82
83
  SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget());
@@ -90,7 +91,7 @@ Txid SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDesti
90
91
  boost::signals2::scoped_connection c(wallet.NotifyTransactionChanged.connect([&txid](const Txid& hash, ChangeType status) {
91
92
  if (status == CT_NEW) txid = hash;
92
93
  }));
93
- ConfirmSend(/*text=*/nullptr, confirm_type);
94
+ ConfirmSend(confirmation_text, confirm_type);
94
95
  bool invoked = QMetaObject::invokeMethod(&sendCoinsDialog, "sendButtonClicked", Q_ARG(bool, false));
95
96
  assert(invoked);
96
97
  return txid;
@@ -265,6 +266,8 @@ public:
265
266
  // QT_QPA_PLATFORM=cocoa build/bin/test_bitcoin-qt # macOS
266
267
  void TestGUI(interfaces::Node& node, const std::shared_ptr<CWallet>& wallet)
267
268
  {
269
+ wallet->m_signal_rbf = false;
270
+
268
271
  // Create widgets for sending coins and listing transactions.
269
272
  std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
270
273
  MiniGUI mini_gui(node, platformStyle.get());
@@ -284,19 +287,42 @@ void TestGUI(interfaces::Node& node, const std::shared_ptr<CWallet>& wallet)
284
287
  // Send two transactions, and verify they are added to transaction list.
285
288
  TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
286
289
  QCOMPARE(transactionTableModel->rowCount({}), 105);
287
- Txid txid1 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, /*rbf=*/false);
288
- Txid txid2 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 10 * COIN, /*rbf=*/true);
290
+ QCheckBox* rbf_checkbox = sendCoinsDialog.findChild<QCheckBox*>("optInRBF");
291
+ QVERIFY(rbf_checkbox);
292
+ QCOMPARE(rbf_checkbox->text(), "Enable Replace-By-Fee");
293
+ QVERIFY(rbf_checkbox->focusPolicy() != Qt::NoFocus);
294
+ QVERIFY(!rbf_checkbox->isChecked());
295
+
296
+ QString no_rbf_confirmation;
297
+ Txid txid1 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, /*rbf=*/false, QMessageBox::Yes, &no_rbf_confirmation);
298
+ QString rbf_confirmation;
299
+ Txid txid2 = SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 10 * COIN, /*rbf=*/true, QMessageBox::Yes, &rbf_confirmation);
300
+ QVERIFY(!SignalsOptInRBF(*wallet->mapWallet.at(txid1).tx));
301
+ QVERIFY(SignalsOptInRBF(*wallet->mapWallet.at(txid2).tx));
302
+ QVERIFY(no_rbf_confirmation.contains("Not signalling Replace-By-Fee, BIP-125."));
303
+ QVERIFY(rbf_confirmation.contains("signals Replace-By-Fee (BIP-125)"));
304
+
305
+ wallet->m_signal_rbf = true;
306
+ SendCoinsDialog default_rbf_dialog(platformStyle.get());
307
+ default_rbf_dialog.setModel(&walletModel);
308
+ QVERIFY(default_rbf_dialog.findChild<QCheckBox*>("optInRBF")->isChecked());
309
+ QString default_on_override_confirmation;
310
+ Txid txid3 = SendCoins(*wallet.get(), default_rbf_dialog, PKHash(), COIN, /*rbf=*/false, QMessageBox::Yes, &default_on_override_confirmation);
311
+ QVERIFY(!SignalsOptInRBF(*wallet->mapWallet.at(txid3).tx));
312
+ QVERIFY(default_on_override_confirmation.contains("Not signalling Replace-By-Fee, BIP-125."));
289
313
  // Transaction table model updates on a QueuedConnection, so process events to ensure it's updated.
290
314
  qApp->processEvents();
291
- QCOMPARE(transactionTableModel->rowCount({}), 107);
315
+ QCOMPARE(transactionTableModel->rowCount({}), 108);
292
316
  QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
293
317
  QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
318
+ QVERIFY(FindTx(*transactionTableModel, txid3).isValid());
294
319
 
295
320
  // Call bumpfee. Test canceled fullrbf bump, canceled bip-125-rbf bump, passing bump, and then failing bump.
296
321
  BumpFee(transactionView, txid1, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/true);
297
322
  BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/true);
298
323
  BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/false);
299
324
  BumpFee(transactionView, txid2, /*expectDisabled=*/true, /*expectError=*/"already bumped", /*cancel=*/false);
325
+ BumpFee(transactionView, txid3, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/true);
300
326
 
301
327
  // Check current balance on OverviewPage
302
328
  OverviewPage overviewPage(platformStyle.get());
@@ -435,6 +461,34 @@ void TestGUIWatchOnly(interfaces::Node& node, TestChain100Setup& test)
435
461
  PartiallySignedTransaction psbt;
436
462
  std::string err;
437
463
  QVERIFY(DecodeRawPSBT(psbt, MakeByteSpan(*decoded_psbt), err));
464
+ QVERIFY(!SignalsOptInRBF(CTransaction{*psbt.tx}));
465
+
466
+ SendCoinsDialog rbf_psbt_dialog(platformStyle.get());
467
+ rbf_psbt_dialog.setModel(&walletModel);
468
+ rbf_psbt_dialog.getCoinControl()->destChange = PKHash{test.coinbaseKey.GetPubKey()};
469
+ QTimer rbf_timer;
470
+ rbf_timer.setInterval(500);
471
+ QObject::connect(&rbf_timer, &QTimer::timeout, [&](){
472
+ for (QWidget* widget : QApplication::topLevelWidgets()) {
473
+ if (widget->inherits("QMessageBox") && widget->objectName().compare("psbt_copied_message") == 0) {
474
+ QMessageBox* dialog = qobject_cast<QMessageBox*>(widget);
475
+ QAbstractButton* button = dialog->button(QMessageBox::Discard);
476
+ button->setEnabled(true);
477
+ button->click();
478
+ rbf_timer.stop();
479
+ break;
480
+ }
481
+ }
482
+ });
483
+ rbf_timer.start(500);
484
+
485
+ SendCoins(*wallet.get(), rbf_psbt_dialog, PKHash(), 5 * COIN, /*rbf=*/true, QMessageBox::Save);
486
+ decoded_psbt = DecodeBase64(QApplication::clipboard()->text().toStdString());
487
+ QVERIFY(decoded_psbt);
488
+ psbt = {};
489
+ err.clear();
490
+ QVERIFY(DecodeRawPSBT(psbt, MakeByteSpan(*decoded_psbt), err));
491
+ QVERIFY(SignalsOptInRBF(CTransaction{*psbt.tx}));
438
492
  }
439
493
 
440
494
  void TestGUI(interfaces::Node& node)