v30.3-roots.1 · Commit 26: [PATCH 26/68] feat(qt): enhance privacy-aware coin control
src/qt/test/wallettests.cpp
Before: src/qt/test/wallettests.cpp · After: src/qt/test/wallettests.cpp
File metadata
index f879ef70db688a472bd9bf6020e2b7281f9216f8..13952ea2dca9828d151144b01a72686e9d18322e 100644
Download original patch · Release notes
Diff rows 1–125 of 125. 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
|
@@ -10,9 +10,11 @@
|
|
|
10
10
|
#include <interfaces/node.h>
|
|
11
11
|
#include <key_io.h>
|
|
12
12
|
#include <logging.h>
|
|
13
|
+
#include <policy/feerate.h>
|
|
13
14
|
#include <qt/bitcoinamountfield.h>
|
|
14
15
|
#include <qt/bitcoinunits.h>
|
|
15
16
|
#include <qt/clientmodel.h>
|
|
17
|
+
#include <qt/coincontroldialog.h>
|
|
16
18
|
#include <qt/optionsmodel.h>
|
|
17
19
|
#include <qt/overviewpage.h>
|
|
18
20
|
#include <qt/platformstyle.h>
|
|
@@ -49,9 +51,11 @@
|
|
|
49
51
|
#include <QLineEdit>
|
|
50
52
|
#include <QObject>
|
|
51
53
|
#include <QPushButton>
|
|
54
|
+
#include <QRadioButton>
|
|
52
55
|
#include <QSettings>
|
|
53
56
|
#include <QTest>
|
|
54
57
|
#include <QTimer>
|
|
58
|
+
#include <QTreeWidget>
|
|
55
59
|
#include <QVBoxLayout>
|
|
56
60
|
#include <QTextEdit>
|
|
57
61
|
#include <QListView>
|
|
@@ -427,6 +431,82 @@ void TestGUI(interfaces::Node& node, const std::shared_ptr<CWallet>& wallet)
|
|
|
427
431
|
// Check 'UseAvailableBalance' functionality
|
|
428
432
|
VerifyUseAvailableBalance(sendCoinsDialog, walletModel);
|
|
429
433
|
|
|
434
|
+
// The coin control view presents wallet-owned facts and keeps filtering a
|
|
435
|
+
// display-only operation: it must not alter the selected outpoints.
|
|
436
|
+
CoinControlDialog coin_control_dialog(*sendCoinsDialog.getCoinControl(), &walletModel, platformStyle.get());
|
|
437
|
+
QTreeWidget* coin_tree = coin_control_dialog.findChild<QTreeWidget*>("treeWidget");
|
|
438
|
+
QLineEdit* coin_filter = coin_control_dialog.findChild<QLineEdit*>("lineEditFilter");
|
|
439
|
+
QLabel* available = coin_control_dialog.findChild<QLabel*>("labelAvailable");
|
|
440
|
+
QLabel* fee_rate = coin_control_dialog.findChild<QLabel*>("labelCoinControlFeeRate");
|
|
441
|
+
QLabel* rbf_summary = coin_control_dialog.findChild<QLabel*>("labelCoinControlRbf");
|
|
442
|
+
QLabel* selection_notice = coin_control_dialog.findChild<QLabel*>("labelSelectionNotice");
|
|
443
|
+
QVERIFY(coin_tree && coin_filter && available && fee_rate && rbf_summary && selection_notice);
|
|
444
|
+
QCOMPARE(coin_tree->headerItem()->text(6), "Status");
|
|
445
|
+
QCOMPARE(coin_tree->headerItem()->text(7), "Effective value");
|
|
446
|
+
QCOMPARE(coin_tree->headerItem()->text(8), "Input bytes");
|
|
447
|
+
QVERIFY(available->text().contains("eligible"));
|
|
448
|
+
QVERIFY(rbf_summary->text().contains("Replace-By-Fee"));
|
|
449
|
+
QCOMPARE(coin_filter->accessibleName(), "Filter coin selection");
|
|
450
|
+
QVERIFY(coin_tree->accessibleDescription().contains("Status column"));
|
|
451
|
+
const auto selected_before_filter = sendCoinsDialog.getCoinControl()->ListSelected();
|
|
452
|
+
coin_filter->setText("not-a-wallet-coin");
|
|
453
|
+
qApp->processEvents();
|
|
454
|
+
for (int row = 0; row < coin_tree->topLevelItemCount(); ++row) QVERIFY(coin_tree->topLevelItem(row)->isHidden());
|
|
455
|
+
QVERIFY(sendCoinsDialog.getCoinControl()->ListSelected() == selected_before_filter);
|
|
456
|
+
coin_filter->clear();
|
|
457
|
+
QVERIFY(coin_tree->focusPolicy() != Qt::NoFocus);
|
|
458
|
+
QVERIFY(QMetaObject::invokeMethod(&coin_control_dialog, "walletChanged"));
|
|
459
|
+
QVERIFY(!sendCoinsDialog.getCoinControl()->HasSelected());
|
|
460
|
+
QVERIFY(!selection_notice->isHidden());
|
|
461
|
+
QVERIFY(selection_notice->text().contains("cleared"));
|
|
462
|
+
coin_control_dialog.reject();
|
|
463
|
+
|
|
464
|
+
// Effective value must use the active coin-control fee rate, not fall back
|
|
465
|
+
// to face value. Check the formatted value, its numeric sorting key, and
|
|
466
|
+
// the item sorting implementation independently of localized labels.
|
|
467
|
+
const CFeeRate effective_fee_rate{1000};
|
|
468
|
+
const auto coin_groups = walletModel.wallet().listCoins();
|
|
469
|
+
QVERIFY(!coin_groups.empty());
|
|
470
|
+
const COutPoint effective_outpoint{std::get<0>(coin_groups.begin()->second.front())};
|
|
471
|
+
const auto effective_coins = walletModel.wallet().getCoins({effective_outpoint}, effective_fee_rate);
|
|
472
|
+
QCOMPARE(effective_coins.size(), 1U);
|
|
473
|
+
const auto& effective_coin = effective_coins.front();
|
|
474
|
+
QVERIFY(effective_coin.effective_value);
|
|
475
|
+
QVERIFY(*effective_coin.effective_value < effective_coin.txout.nValue);
|
|
476
|
+
|
|
477
|
+
wallet::CCoinControl effective_control;
|
|
478
|
+
effective_control.m_feerate = effective_fee_rate;
|
|
479
|
+
CoinControlDialog effective_dialog(effective_control, &walletModel, platformStyle.get());
|
|
480
|
+
QRadioButton* list_mode = effective_dialog.findChild<QRadioButton*>("radioListMode");
|
|
481
|
+
QTreeWidget* effective_tree = effective_dialog.findChild<QTreeWidget*>("treeWidget");
|
|
482
|
+
QVERIFY(list_mode && effective_tree);
|
|
483
|
+
list_mode->setChecked(true);
|
|
484
|
+
qApp->processEvents();
|
|
485
|
+
QTreeWidgetItem* effective_item{nullptr};
|
|
486
|
+
for (int row = 0; row < effective_tree->topLevelItemCount(); ++row) {
|
|
487
|
+
QTreeWidgetItem* item = effective_tree->topLevelItem(row);
|
|
488
|
+
if (item->data(3, Qt::UserRole).toString() == QString::fromStdString(effective_outpoint.hash.GetHex()) &&
|
|
489
|
+
item->data(3, Qt::UserRole + 1).toUInt() == effective_outpoint.n) {
|
|
490
|
+
effective_item = item;
|
|
491
|
+
break;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
QVERIFY(effective_item);
|
|
495
|
+
QCOMPARE(effective_item->text(7), BitcoinUnits::format(walletModel.getOptionsModel()->getDisplayUnit(), *effective_coin.effective_value));
|
|
496
|
+
QCOMPARE(effective_item->data(7, Qt::UserRole).toLongLong(), qlonglong{*effective_coin.effective_value});
|
|
497
|
+
|
|
498
|
+
QTreeWidget effective_sort_tree;
|
|
499
|
+
effective_sort_tree.setColumnCount(9);
|
|
500
|
+
auto* larger_effective = new CCoinControlWidgetItem(&effective_sort_tree);
|
|
501
|
+
larger_effective->setText(7, "0.00000001");
|
|
502
|
+
larger_effective->setData(7, Qt::UserRole, qlonglong{*effective_coin.effective_value + 1});
|
|
503
|
+
auto* smaller_effective = new CCoinControlWidgetItem(&effective_sort_tree);
|
|
504
|
+
smaller_effective->setText(7, "9.99999999");
|
|
505
|
+
smaller_effective->setData(7, Qt::UserRole, qlonglong{*effective_coin.effective_value});
|
|
506
|
+
effective_sort_tree.sortItems(7, Qt::AscendingOrder);
|
|
507
|
+
QCOMPARE(effective_sort_tree.topLevelItem(0)->data(7, Qt::UserRole).toLongLong(), qlonglong{*effective_coin.effective_value});
|
|
508
|
+
effective_dialog.reject();
|
|
509
|
+
|
|
430
510
|
// Send two transactions, and verify they are added to transaction list.
|
|
431
511
|
TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
|
|
432
512
|
QCOMPARE(transactionTableModel->rowCount({}), 105);
|
|
@@ -447,6 +527,10 @@ void TestGUI(interfaces::Node& node, const std::shared_ptr<CWallet>& wallet)
|
|
|
447
527
|
}
|
|
448
528
|
QVERIFY(no_rbf_confirmation.contains("Not signalling Replace-By-Fee, BIP-125."));
|
|
449
529
|
QVERIFY(rbf_confirmation.contains("signals Replace-By-Fee (BIP-125)"));
|
|
530
|
+
QVERIFY(rbf_confirmation.contains("Effective coin control"));
|
|
531
|
+
QVERIFY(rbf_confirmation.contains("Inputs:"));
|
|
532
|
+
QVERIFY(rbf_confirmation.contains("Fee rate:"));
|
|
533
|
+
QVERIFY(rbf_confirmation.contains("Change:"));
|
|
450
534
|
|
|
451
535
|
wallet->m_signal_rbf = true;
|
|
452
536
|
SendCoinsDialog default_rbf_dialog(platformStyle.get());
|
|
@@ -600,7 +684,10 @@ void TestGUIWatchOnly(interfaces::Node& node, TestChain100Setup& test)
|
|
|
600
684
|
timer.start(500);
|
|
601
685
|
|
|
602
686
|
// Send tx and verify PSBT copied to the clipboard.
|
|
603
|
-
SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, /*rbf=*/false, QMessageBox::Save);
|
|
687
|
+
QString psbt_confirmation;
|
|
688
|
+
SendCoins(*wallet.get(), sendCoinsDialog, PKHash(), 5 * COIN, /*rbf=*/false, QMessageBox::Save, &psbt_confirmation);
|
|
689
|
+
QVERIFY(psbt_confirmation.contains("Effective coin control"));
|
|
690
|
+
QVERIFY(psbt_confirmation.contains("Inputs:"));
|
|
604
691
|
const std::string& psbt_string = QApplication::clipboard()->text().toStdString();
|
|
605
692
|
QVERIFY(!psbt_string.empty());
|
|
606
693
|
|