Bitcoin Core  31.0.0
P2P Digital Currency
addressbooktests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2017-present The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
6 #include <qt/test/util.h>
8 
9 #include <interfaces/chain.h>
10 #include <interfaces/node.h>
11 #include <qt/addressbookpage.h>
12 #include <qt/clientmodel.h>
13 #include <qt/editaddressdialog.h>
14 #include <qt/optionsmodel.h>
15 #include <qt/platformstyle.h>
16 #include <qt/qvalidatedlineedit.h>
17 #include <qt/walletmodel.h>
18 
19 #include <key.h>
20 #include <key_io.h>
21 #include <wallet/wallet.h>
22 #include <wallet/test/util.h>
23 #include <walletinitinterface.h>
24 
25 #include <chrono>
26 
27 #include <QApplication>
28 #include <QLineEdit>
29 #include <QMessageBox>
30 #include <QTableView>
31 #include <QTimer>
32 
33 using wallet::AddWallet;
34 using wallet::CWallet;
39 
40 namespace
41 {
42 
47 void EditAddressAndSubmit(
48  EditAddressDialog* dialog,
49  const QString& label, const QString& address, QString expected_msg)
50 {
51  QString warning_text;
52 
53  dialog->findChild<QLineEdit*>("labelEdit")->setText(label);
54  dialog->findChild<QValidatedLineEdit*>("addressEdit")->setText(address);
55 
56  ConfirmMessage(&warning_text, 5ms);
57  dialog->accept();
58  QCOMPARE(warning_text, expected_msg);
59 }
60 
73 void TestAddAddressesToSendBook(interfaces::Node& node)
74 {
75  TestChain100Setup test;
76  auto wallet_loader = interfaces::MakeWalletLoader(*test.m_node.chain, *Assert(test.m_node.args));
77  test.m_node.wallet_loader = wallet_loader.get();
78  node.setContext(&test.m_node);
79  const std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(node.context()->chain.get(), "", CreateMockableWalletDatabase());
80  wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
81  {
82  LOCK(wallet->cs_wallet);
83  wallet->SetupDescriptorScriptPubKeyMans();
84  }
85 
86  auto build_address{[]() {
88  return std::make_pair(dest, QString::fromStdString(EncodeDestination(dest)));
89  }};
90 
91  CTxDestination r_key_dest, s_key_dest;
92 
93  // Add a preexisting "receive" entry in the address book.
94  QString preexisting_r_address;
95  QString r_label("already here (r)");
96 
97  // Add a preexisting "send" entry in the address book.
98  QString preexisting_s_address;
99  QString s_label("already here (s)");
100 
101  // Define a new address (which should add to the address book successfully).
102  QString new_address_a;
103  QString new_address_b;
104 
105  std::tie(r_key_dest, preexisting_r_address) = build_address();
106  std::tie(s_key_dest, preexisting_s_address) = build_address();
107  std::tie(std::ignore, new_address_a) = build_address();
108  std::tie(std::ignore, new_address_b) = build_address();
109 
110  {
111  LOCK(wallet->cs_wallet);
112  wallet->SetAddressBook(r_key_dest, r_label.toStdString(), wallet::AddressPurpose::RECEIVE);
113  wallet->SetAddressBook(s_key_dest, s_label.toStdString(), wallet::AddressPurpose::SEND);
114  }
115 
116  auto check_addbook_size = [&wallet](int expected_size) {
117  LOCK(wallet->cs_wallet);
118  QCOMPARE(static_cast<int>(wallet->m_address_book.size()), expected_size);
119  };
120 
121  // We should start with the two addresses we added earlier and nothing else.
122  check_addbook_size(2);
123 
124  // Initialize relevant QT models.
125  std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
126  OptionsModel optionsModel(node);
127  bilingual_str error;
128  QVERIFY(optionsModel.Init(error));
129  ClientModel clientModel(node, &optionsModel);
130  WalletContext& context = *node.walletLoader().context();
131  AddWallet(context, wallet);
132  WalletModel walletModel(interfaces::MakeWallet(context, wallet), clientModel, platformStyle.get());
133  RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt);
135  editAddressDialog.setModel(walletModel.getAddressTableModel());
136 
137  AddressBookPage address_book{platformStyle.get(), AddressBookPage::ForEditing, AddressBookPage::SendingTab};
138  address_book.setModel(walletModel.getAddressTableModel());
139  auto table_view = address_book.findChild<QTableView*>("tableView");
140  QCOMPARE(table_view->model()->rowCount(), 1);
141 
142  EditAddressAndSubmit(
143  &editAddressDialog, QString("uhoh"), preexisting_r_address,
144  QString(
145  "Address \"%1\" already exists as a receiving address with label "
146  "\"%2\" and so cannot be added as a sending address."
147  ).arg(preexisting_r_address).arg(r_label));
148  check_addbook_size(2);
149  QCOMPARE(table_view->model()->rowCount(), 1);
150 
151  EditAddressAndSubmit(
152  &editAddressDialog, QString("uhoh, different"), preexisting_s_address,
153  QString(
154  "The entered address \"%1\" is already in the address book with "
155  "label \"%2\"."
156  ).arg(preexisting_s_address).arg(s_label));
157  check_addbook_size(2);
158  QCOMPARE(table_view->model()->rowCount(), 1);
159 
160  // Submit a new address which should add successfully - we expect the
161  // warning message to be blank.
162  EditAddressAndSubmit(
163  &editAddressDialog, QString("io - new A"), new_address_a, QString(""));
164  check_addbook_size(3);
165  QCOMPARE(table_view->model()->rowCount(), 2);
166 
167  EditAddressAndSubmit(
168  &editAddressDialog, QString("io - new B"), new_address_b, QString(""));
169  check_addbook_size(4);
170  QCOMPARE(table_view->model()->rowCount(), 3);
171 
172  auto search_line = address_book.findChild<QLineEdit*>("searchLineEdit");
173 
174  search_line->setText(r_label);
175  QCOMPARE(table_view->model()->rowCount(), 0);
176 
177  search_line->setText(s_label);
178  QCOMPARE(table_view->model()->rowCount(), 1);
179 
180  search_line->setText("io");
181  QCOMPARE(table_view->model()->rowCount(), 2);
182 
183  // Check wildcard "?".
184  search_line->setText("io?new");
185  QCOMPARE(table_view->model()->rowCount(), 0);
186  search_line->setText("io???new");
187  QCOMPARE(table_view->model()->rowCount(), 2);
188 
189  // Check wildcard "*".
190  search_line->setText("io*new");
191  QCOMPARE(table_view->model()->rowCount(), 2);
192  search_line->setText("*");
193  QCOMPARE(table_view->model()->rowCount(), 3);
194 
195  search_line->setText(preexisting_r_address);
196  QCOMPARE(table_view->model()->rowCount(), 0);
197 
198  search_line->setText(preexisting_s_address);
199  QCOMPARE(table_view->model()->rowCount(), 1);
200 
201  search_line->setText(new_address_a);
202  QCOMPARE(table_view->model()->rowCount(), 1);
203 
204  search_line->setText(new_address_b);
205  QCOMPARE(table_view->model()->rowCount(), 1);
206 
207  search_line->setText("");
208  QCOMPARE(table_view->model()->rowCount(), 3);
209 }
210 
211 } // namespace
212 
214 {
215 #ifdef Q_OS_MACOS
216  if (QApplication::platformName() == "minimal") {
217  // Disable for mac on "minimal" platform to avoid crashes inside the Qt
218  // framework when it tries to look up unimplemented cocoa functions,
219  // and fails to handle returned nulls
220  // (https://bugreports.qt.io/browse/QTBUG-49686).
221  qWarning() << "Skipping AddressBookTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke "
222  "with 'QT_QPA_PLATFORM=cocoa test_bitcoin-qt' on mac, or else use a linux or windows build.";
223  return;
224  }
225 #endif
226  TestAddAddressesToSendBook(m_node);
227 }
std::unique_ptr< interfaces::Chain > chain
Definition: context.h:76
Bilingual messages:
Definition: translation.h:24
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:183
std::unique_ptr< Wallet > MakeWallet(wallet::WalletContext &context, const std::shared_ptr< wallet::CWallet > &wallet)
Return implementation of Wallet interface.
Definition: interfaces.cpp:668
Open address book for editing.
Line edit that can be marked as "invalid" to show input validation feedback.
interfaces::Node & m_node
CKey GenerateRandomKey(bool compressed) noexcept
Definition: key.cpp:475
void ConfirmMessage(QString *text, std::chrono::milliseconds msec)
Press "Ok" button in message box dialog.
Definition: util.cpp:16
std::unique_ptr< WalletLoader > MakeWalletLoader(Chain &chain, ArgsManager &args)
Return implementation of ChainClient interface for a wallet loader.
Definition: dummywallet.cpp:59
#define LOCK(cs)
Definition: sync.h:258
ArgsManager * args
Definition: context.h:74
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition: walletutil.h:53
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:309
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
Definition: setup_common.h:146
Widget that shows a list of sending or receiving addresses.
Model for Bitcoin network client.
Definition: clientmodel.h:56
Definition: messages.h:21
void accept() override
bool RemoveWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start, std::vector< bilingual_str > &warnings)
Definition: wallet.cpp:163
std::unique_ptr< WalletDatabase > CreateMockableWalletDatabase(MockableData records)
Definition: util.cpp:211
static const PlatformStyle * instantiate(const QString &platformId)
Get style associated with provided platform name, or 0 if not known.
Interface from Qt to configuration data structure for Bitcoin client.
Definition: optionsmodel.h:42
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:48
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, PayToAnchor, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
Definition: addresstype.h:143
Dialog for editing an address and associated information.
WalletContext struct containing references to state shared between CWallet instances, like the reference to the chain interface, and the list of opened wallets.
Definition: context.h:36
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:294
interfaces::WalletLoader * wallet_loader
Definition: context.h:82
node::NodeContext m_node
Definition: setup_common.h:66
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:69
bool AddWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
Definition: wallet.cpp:151
#define Assert(val)
Identity function.
Definition: check.h:113