Skip to content
Bitcoin Roots

v29.4-roots.2 · Commit 16: [PATCH 16/21] 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. 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
  uint256 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 @@ uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDe
90
91
  boost::signals2::scoped_connection c(wallet.NotifyTransactionChanged.connect([&txid](const uint256& 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;
@@ -273,6 +274,8 @@ public:
273
274
  // QT_QPA_PLATFORM=cocoa build/bin/test_bitcoin-qt # macOS
274
275
  void TestGUI(interfaces::Node& node, const std::shared_ptr<CWallet>& wallet)
275
276
  {
277
+ wallet->m_signal_rbf = false;
278
+
276
279
  // Create widgets for sending coins and listing transactions.
277
280
  std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
278
281
  MiniGUI mini_gui(node, platformStyle.get());
@@ -292,19 +295,42 @@ void TestGUI(interfaces::Node& node, const std::shared_ptr<CWallet>& wallet)
292
295
  // Send two transactions, and verify they are added to transaction list.
293
296
  TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
294
297
  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);
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."));
297
321
  // Transaction table model updates on a QueuedConnection, so process events to ensure it's updated.
298
322
  qApp->processEvents();
299
- QCOMPARE(transactionTableModel->rowCount({}), 107);
323
+ QCOMPARE(transactionTableModel->rowCount({}), 108);
300
324
  QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
301
325
  QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
326
+ QVERIFY(FindTx(*transactionTableModel, txid3).isValid());
302
327
 
303
328
  // Call bumpfee. Test disabled, canceled, enabled, then failing cases.
304
329
  BumpFee(transactionView, txid1, /*expectDisabled=*/true, /*expectError=*/"not BIP 125 replaceable", /*cancel=*/false);
305
330
  BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/true);
306
331
  BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/false);
307
332
  BumpFee(transactionView, txid2, /*expectDisabled=*/true, /*expectError=*/"already bumped", /*cancel=*/false);
333
+ BumpFee(transactionView, txid3, /*expectDisabled=*/true, /*expectError=*/"not BIP 125 replaceable", /*cancel=*/false);
308
334
 
309
335
  // Check current balance on OverviewPage
310
336
  OverviewPage overviewPage(platformStyle.get());
@@ -443,6 +469,34 @@ void TestGUIWatchOnly(interfaces::Node& node, TestChain100Setup& test)
443
469
  PartiallySignedTransaction psbt;
444
470
  std::string err;
445
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}));
446
500
  }
447
501
 
448
502
  void TestGUI(interfaces::Node& node)